题目链接;题目传送门
题目大意:给出的字符串,每个字符建立一种与0-25的对应关系。然后每个字符串看成是一个26进制的数。问能获得的数的总和的最大值。(最后对1e9+7取模)。(不能有前导零 即字符串长度大于1,那么第一位不能为0)
思路:
所有的字符串,无非就是每个字符的贡献乘上赋予的映射的权值。所以我们可以按照贡献排序。贡献其实就是跟位置有关的系数,我们把对应的位置记录下来,转换成一个26进制数。
官方题解:每个字符对答案的贡献都可以看作一个 26 进制的数字,问题相当于要给这些贡献加一个 0 到 25 的权重使得答案最大。最大的数匹配 25,次大的数匹配 24,依次类推。排序后这样依次贪心即可,唯一注意的是不能出现前导 0。#include <bits/stdc++.h>
using namespace std;
const int maxn =1e5+7;
const long long mod=1e9+7;
long long k[maxn];//贡献度标准
int n;
struct node
{
int id;
int num[maxn];
bool operator <(const node &a)const
{
for(int j=100000;j>=0;j--)
if(num[j]!=a.num[j])
return num[j] >a.num[j];//从大到小排序
return 0;
}
}p[30];
string s[maxn];
long long num[30];//每个字母的贡献度
bool ha[30];//前导0
int main()
{
k[0]=1;
for(int i=1;i<=100000;i++)
{
k[i]=(k[i-1]*26)%mod;
}
int cas=0;
while(scanf("%d",&n)!=EOF)
{
for(int i=0;i<26;i++)
{
for(int j=0; j<=100000; j++)p[i].num[j]=0;
p[i].id=i;
ha[i]=0;
}
for(int i=0;i<n;i++)
{
cin>>s[i];
int len=s[i].size();
if(len>1)//位数大于一位 即存在前导零
{
ha[s[i][0]-'a']=1;
}
for(int ii=len-1,j=0;ii>=0;ii--,j++)//记录每个字母的贡献度
{
int t=s[i][ii]-'a';
p[t].num[j]++;
}
}
for(int i=0;i<26;i++)
{
for(int j=0;j<=100000;j++)//进位 目的是为了之后的排序比较
{
p[i].num[j+1]+=p[i].num[j]/26;
p[i].num[j]%=26;
}
}
sort(p,p+26);
for(int i=25;i>=0;i--)//按照贡献率 贡献大的字母代表的数要大
{
num[p[25-i].id]=i;
}
int t=25;
while(ha[p[t].id]&&t)//判断代表0的字母是否是前导0 是的话 0只能往比他贡献大的字母转化
{
swap(num[p[t].id],num[p[t-1].id]);
t--;
}
long long ans=0;
for(int i=0;i<n;i++)
{
int len=s[i].size();
for(int j=0;j<len;j++)
{
ans=(ans+num[s[i][j]-'a']*k[len -1-j]%mod)%mod;
}
}
cout<<"Case #"<<++cas<<": "<<ans<<endl;
}
return 0;
}