HDU6034 Balala Power!

来源:互联网 发布:windows xp原装系统 编辑:程序博客网 时间:2024/06/05 07:35

Balala Power!


这道题的题意就是给你n个字符串,让你对每个字符赋值(0~25)(注意,每种字符只能赋一个值),然后让你求这些字符的26进制的和的最大值,并且用十进制输出这个最大值。

解释一下样例,
第一个样例,用25对a赋值即可。
第二个样例,用25对a赋值,用24对b赋值(反过来也可以),aa = 25 * 26 + 25 = 675, bb = 24 * 26 + 24 = 648,
aa + bb = 675 + 648 = 1323
第三个样例,用25对a赋值,用24对b赋值,用23对c赋值,a = 25, ba = 24 * 26 + 25 = 649, abc = 25 * 26^2 + 24 * 26 + 23 = 17547, a + ba + abc = 18221
做完这几个样例,相信大家有点感觉了,只要对最高位上的出现次数最多的字符赋最大的值就可以了,如果最高位上的字符一样多,就右找。
还有一点要注意的是这道题的字符串,如果长度大于等于2,第一位不能赋零。就是说比如给你30个a,30个b……30个y 和一个za,按照之前的排序规则,z出现次数最少,就应该赋零,在这条规则下,z只能被赋1,而b~y中的任意一种字母被赋零。

代码如下:

#include<bits/stdc++.h>using namespace std;typedef long long ll;const int maxn = 100020;const int mod = 1e9 + 7;int base[maxn]; //预处理基数数组int sum[maxn];int num[26][maxn]; //第一维表示a~z对应的数,a对应1,b对应2……,第二位表示该字符出现的次数int maxlen = 0;int vis[26];char str[maxn];int rate[26];bool cmp(int a, int b)//以出现次数更少且所在位更低的字符为优先排序(因为待会要反转字符串,最高位的其实是最低位){    for(int i = maxlen - 1; i >= 0; --i)    {        if(num[a][i] != num[b][i])        {            return num[a][i] < num[b][i];        }    }    return 0;}int main(){    base[0] = 1;    for(int i = 1; i < maxn; ++i)//预处理基数数组    {        base[i]= (ll)base[i-1] * 26 % mod ;    }    int cas=0, n;    while(~scanf("%d", &n))    {        memset(vis, 0, sizeof(vis));        memset(sum, 0, sizeof(sum));        memset(num, 0, sizeof(num));        maxlen=0;        for(int i = 0; i < n; ++i)        {            scanf("%s", str);            int len = strlen(str);            if(len > 1) vis[str[0] - 'a'] = 1; //对于字符串长度大于等于2字符串的第一个字母进行标记,不能被赋零。            reverse(str, str + len);//反转字符串,接下来的操作时下标可以写的方便些。            for(int j = 0; j < len; ++ j)//记录每个字符出现次数            {                ++ num[str[j] - 'a'][j];                sum[str[j] - 'a']+= base[j];//同时将每个字符在各个位的基数幂的和求出来,这样待会直接乘对应的(0~25)就行了。                if(sum[str[j] - 'a'] >= mod)//取模                {                    sum[str[j] - 'a']-= mod;                }            }            maxlen = max(maxlen,len);//更新字符串最大长度        }        for(int i = 0; i < 26; ++i)//为计算字符串中那个是最高位出现次是最多的做准备,逢26进1,最高位进位就更新maxlen        {            for(int j = 0; j < maxlen; ++j)            {                num[i][j + 1]+= num[i][j]/26;                num[i][j]%= 26;            }            while(num[i][maxlen])            {                num[i][maxlen + 1]+= num[i][maxlen] / 26;                num[i][maxlen++]%= 26;            }            rate[i]=i;        }        sort(rate, rate + 26, cmp);//排序        int pos = -1;        for(int i = 0; i < 26; ++i)//找出要赋零的字符        {            if(!vis[rate[i]])            {                pos = rate[i];                break;            }        }        int dic = 25;        ll ans = 0;        for(int i = 25; i >= 0; --i)        {            if(rate[i] != pos)            {                ans+= (ll)(dic--) * sum[rate[i]] % mod;//直接乘以相应的权值,算出最后的答案                ans%= mod;            }        }        ans = ans % mod;        cas++;        printf("Case #%d: %lld\n", cas, ans);    }}
原创粉丝点击