题意:给a-z字符赋上0-25每个数字只能赋一次求怎么赋值使得数值最大然后取膜1e9+7
题解:给拥有最大位数并且最大位数的拥有个数最多的赋值最大然后依次递减记得处理前导不能为0的情况
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long int ll;
const int mx = 1e5+5;
const int L = 1e5;
const ll mod = 1e9+7;
char s[mx];
ll x[mx];
struct node{
int num[mx],low,date;
bool operator<(const node &a)const{
for(int i = 1; i < L; i++)
if(num[i]!=a.num[i])
return num[i]>a.num[i];
return num[L]>a.num[L];
}
}a[30];
bool vis[30],mark[30];
int main(){
x[L] = 1;
for(int i = L-1; i >= 1; i--)
x[i] = x[i+1]*26%mod;
int casei = 1,n;
while(scanf("%d",&n)!=EOF){
for(int i = 0; i < 26; i++){
vis[i] = 0;
mark[i] = 0;
a[i].low = i;
memset(a[i].num,0,sizeof(a[i].num));
}
for(int i = 1; i <= n; i++){
scanf("%s",s+1);
int len = strlen(s+1);
vis[s[1]-'a'] = 1;
for(int j = 1; j <= len; j++){
a[s[j]-'a'].num[L-(len-j)]++;
mark[s[j]-'a'] = 1;
}
}
int cnt = 0;
for(int i = 0; i < 26; i++){
if(mark[i])
cnt++;
for(int j = L; j >= 2; j--){
a[i].num[j-1] += a[i].num[j]/26;
a[i].num[j] %= 26;
}
}
sort(a,a+26);
if(cnt == 26){ //如果26个字母都出现过
if(vis[a[25].low]){ //判断是否最后一个前导为0
int p;
for(int i = 25; i >= 0; i--)
if(!vis[a[i].low]){
p = i; //找到第一个不是前导的位置
break;
}
for(int i = 0; i < 26; i++) //从上到下依次递减赋值
if(i!=p)
a[i].date = --cnt;
else
a[i].date = 0; //排序完最小的不是前导的赋值为0
}
else
for(int i = 0; i < 26; i++)
a[i].date = 25-i;
}
else
for(int i = 0; i < 26; i++)
a[i].date = 25-i;
ll ans = 0;
for(int i = 0; i < 26; i++)if(mark[a[i].low]){ //判断一下有没有这个字母
for(int j = 1; j <= L; j++)
if(a[i].num[j]) //如果这个位数有数值再进行运算减少不必要的时间
ans = (ans+a[i].num[j]*a[i].date*x[j])%mod;
}
ans%=mod;
printf("Case #%d: %I64d\n",casei++,ans);
}
return 0;
}