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);
}
}