题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6034
把所有的字符串用 26 的多项式表示,所有字符串的和就是多项式相加,按照字母提取公因式,整理成26进制,作为字母的系数,按照系数给字母排序,系数越大的字母分配的权值越大。
关于前导零的处理,可以在排完序之后,从不是首字母的字母中选出排名最靠后的那一个,记录为0,最后分配权值和累加答案的时候跳过。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string.h>
#include <stdlib.h>
#include <set>
#include <algorithm>
using namespace std;
typedef long long unsigned int ull;
typedef long long ll;
const int maxL = 100000 + 10;
const ull mod = 1e9 + 7;
int f[27][maxL];
ull expp[maxL];
char S[maxL];
bool first[26];
int a[26];
ull w[26];
int n;
void init(){
expp[0] = 1;
for (int i=1; i<maxL; i++){
expp[i] = expp[i-1] * 26;
expp[i] %= mod;
}
}
int cmp(int a, int b){
if (f[a][0] != f[b][0])
return f[a][0] > f[b][0];
for (int i=f[a][0]; i>=1; i--){
if (f[a][i] != f[b][i])
return f[a][i] > f[b][i];
}
return 0;
}
int main()
{
init();
int t = 0;
while (~scanf("%d", &n)){
t++;
memset(f, 0, sizeof(f));
memset(first, false, sizeof(first));
memset(w, 0, sizeof(w));
for (int i=0; i<n; i++){
scanf("%s", S);
first[S[0] - 'a'] = true;
int len = strlen(S);
reverse(S, S+len);
for (int j=0; j<len; j++){
int k = S[j] - 'a';
f[k][j+1]++;
if (j+1 > f[k][0]) f[k][0] = j+1;
w[k] = (w[k] + expp[j]) % mod;
}
}
for (int i=0; i<26; i++){
for (int j=1; j<=f[i][0]; j++){
f[i][j+1] += f[i][j] / 26;
f[i][j] %= 26;
}
int len = f[i][0];
while (f[i][len] > 0){
f[i][len+1] += f[i][len] / 26;
f[i][len] %= 26;
len++;
}
f[i][0] = len;
}
for (int i=0; i<26; i++) a[i] = i;
sort(a, a+26, cmp);
int zero = 0;//记录权值为 0 的字母
for (int i=25; i>=0; i--){
if (!first[a[i]]){
zero = a[i];
break;
}
}
ull ans = 0;
int x = 25;
for (int i=0; i<26; i++){
if (zero == a[i]) continue;
ans += (w[a[i]] * (ull)(x--)) % mod; //这里不要用(26-i-1),因为可能会跳过权值为0的字母
ans %= mod;
}
cout << "Case #" << t << ": " << ans << endl;
}
return 0;
}