hdu 6034 2017 Multi-University Training Contest - Team 1 B Balala Power! (贪心)
http://acm.hdu.edu.cn/showproblem.php?pid=6034
题意:
有一个仅由小写字母组成的字符串,要求将a..z的字母,对应到0..25,每个数字只能被一个字母对应,得到一个26进制的数,现在问这个数最大是多少。注意不允许有前导0,除非这个数本身就是0.
思路:
贪心。看哪个字母的权值最大。
可以用类似高精度加法的方式处理。
对于前导0的部分,用一个bool标记首位(如果字符串长度为1就不标记)
对于26个高精度数的排序,可以用交换id的技巧。
以及,如果排序之后,发现权值最小的数被对应到数字0,但是又在某个长度大于1的字符串的首字母位置出现过。
我初始想当然得,把该字母和最小的可以出现在首位的字母交换....
然而这很错啊?
实际上,更优秀做法是,找到第一个可以出现在首位的字母,然后从该字母后面到结尾,依次前移一位,最后把这个可以出现在首位的字母放在最后。
比如这组数据:
7 abcdefghijklmnopqrstuvwxyz zz yy xx ww uu vv
权值按照从大到小排列
z u v w x y t 显然不如 u v w x y z t 优
/* ***********************************************
Author :111qqz
Created Time :2017年11月01日 星期三 00时56分26秒
File Name :6034.cpp
************************************************ */
1#include <bits/stdc++.h>
2#define PB push_back
3#define fst first
4#define sec second
5#define lson l,m,rt<<1
6#define rson m+1,r,rt<<1|1
7#define ms(a,x) memset(a,x,sizeof(a))
8typedef long long LL;
9#define pi pair < int ,int >
10#define MP make_pair
1using namespace std;
2const double eps = 1E-8;
3const int dx4[4]={1,0,0,-1};
4const int dy4[4]={0,-1,1,0};
5const int inf = 0x3f3f3f3f;
6const int N=1E5+7;
7const LL mod =1E9+7;
8int n;
9string st[N];
10int cnt[26][N];
11int maxlen;
12int id[26];
13int power[26];
14LL base26[N];
15bool Beg[26];
16void init()
17{
18 ms(Beg,false);
19 ms(cnt,0);
20 maxlen = 0 ;
21 for ( int i = 0 ; i < 26 ; i++) id[i] = i;
22}
23bool small(int *a,int *b)
24{
25 for ( int i = maxlen-1 ; i >= 0 ; i--)
26 {
27 if (a[i]<b[i]) return true;
28 if (a[i]>b[i]) return false;
29 }
30 return false;
31}
32int main()
33{
34 #ifndef ONLINE_JUDGE
35 freopen("./in.txt","r",stdin);
36 #endif
37 int cas = 0 ;
38 base26[0] = 1;
39 for ( int i = 1 ; i < N ; i++) base26[i] = base26[i-1] * 26 % mod;
40 while (~scanf("%d",&n))
41 {
42 init();
43 for ( int i = 1 ; i <= n ; i++)
44 {
45 cin>>st[i];
46 int len = st[i].length();
47 // cout<<"len:"<<len<<endl;
48 maxlen = max(len,maxlen);
49 for ( int j = 0 ; j < len ; j++)
50 {
51 int v = st[i][j]-'a';
52 cnt[v][len-j-1]++;
53 }
54 //如果只有一个字母,不要打首字母标记
55 if (len>1)
56 Beg[st[i][0]-'a'] = true;
57 //忘了不能右前导0的条件了。。。
58 }
59 for ( int i = 0 ; i < 26 ; i++)
60 {
61 for ( int j = 0 ; j < maxlen ; j++)
62 {
63 cnt[i][j+1] += cnt[i][j]/26;
64 cnt[i][j]%=26;
65 }
66 while (cnt[i][maxlen]>0)
67 {
68 cnt[i][maxlen+1] += cnt[i][maxlen]/26;
69 cnt[i][maxlen]%=26;
70 maxlen++;
71 }
72 }
1 for ( int i = 0 ; i < 26 ; i++)
2 for ( int j = i+1 ; j < 26 ; j++)
3 if (small(cnt[id[i]],cnt[id[j]]))
4 swap(id[i],id[j]);
5// for (int i = 0 ; i < 26 ; i++) printf("id[%d]:%c%c",i,char(id[i]+'a'),i==25?'\n':'\n');
1 int notBEG = -1;
2 if (Beg[id[25]])
3 {
4 for ( int i = 24 ; i >= 0 ; i--)
5 {
6 if (!Beg[id[i]])
7 {
8 notBEG = i;
9 break;
10 }
11 }
12 }
13 //cout<<"notBEG:"<<notBEG<<endl;
14 if (notBEG!=-1)
15 {
16 int tmp = id[notBEG];
17 for ( int i = notBEG +1 ; i < 26 ; i++) id[i-1] = id[i];
18 id[25] = tmp;
19 }
20 //for ( int i = 0 ; i < 26 ; i++) printf("id[%d]:%c\n",i,char(id[i]+'a'));
1 for ( int i = 0 ; i < 26 ; i++) power[id[i]] = 25-i;
2 LL ans = 0;
3 for ( int i = 1 ; i <= n ; i++)
4 {
5 int len = st[i].length();
6 for ( int j = 0 ; j < len ; j++)
7 {
8 int pos = len-j-1;
9 int v = st[i][j]-'a';
10 LL tmp = (base26[pos]*power[v])%mod;
11 // cout<<"tmp:"<<tmp<<endl;
12 ans = (ans + tmp)%mod;
13 }
14 }
15 printf("Case #%d: %lld\n",++cas,ans);
}
1 #ifndef ONLINE_JUDGE
2 fclose(stdin);
3 #endif
4 return 0;
5}