思路:算出每一个字母的贡献值,然后按贡献值由小到大赋值0到25,注意要记录那些字母若为0,则出现前置0,如何算贡献值?
记录每一个字母在第几位出现几次,得出一个26进制数,以这个26进制数作为贡献值
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
using namespace std;
const int N = 1e5+10;
const int mod = 1e9+7;
typedef long long ll;
struct node{
int len[N];
int w;
int v;
int L;
}p[26];
bool cmp(node a,node b){
if(a.L != b.L) return a.L < b.L;
for(int i = a.L;i >= 0;i--){
if(a.len[i]==b.len[i]) continue;
return a.len[i]<b.len[i];
}
return 0;
}
bool flag[26];
int n;
string str[N];
int main(){
int cas = 1;
while(~scanf("%d",&n)){
memset(flag,0,sizeof(flag));
for(int i = 0;i < 26;i++){
for(int j = 0;j <= p[i].L;j++){
p[i].len[j]=0;
}
}
for(int i = 0;i < 26;i++){
p[i].L=-1;
p[i].v = 0;
p[i].w = i;
}
for(int i = 0;i < n;i++){
cin>>str[i];
if(str[i].size()>1) flag[str[i][0]-'a'] = 1;
reverse(str[i].begin(),str[i].end());
for(int j = 0;j < str[i].size();j++){
p[str[i][j]-'a'].len[j]++;
}
}
for(int i = 0;i < 26;i++){
for(int j = 0;j < N;j++){
if(p[i].len[j]>=26){
int d = p[i].len[j]/26;
p[i].len[j]%=26;
p[i].len[j+1]+=d;
}
if(p[i].len[j]>0) p[i].L = max(p[i].L,j);
}
}
sort(p,p+26,cmp);
for(int i = 0;i < 26;i++){
p[i].v = i;
}
for(int i = 0;i < 26;i++){
if(flag[p[i].w]&&p[i].v==0){
swap(p[i].v,p[i+1].v);
}
}
ll ans = 0;
ll value[26];
for(int i = 0;i < 26;i++){
value[p[i].w]=p[i].v;
}
for(int i = 0;i < n;i++){
ll now = 1;
for(int j = 0;j < str[i].size();j++){
ans = (ans+(value[str[i][j]-'a']*now)%mod)%mod;
now = (now*26)%mod;
}
}
printf("Case #%d: %lld\n",cas++,ans);
}
return 0;
}