【题目链接】http://acm.hdu.edu.cn/showproblem.php?pid=6034
题目意思
题目大意为:给你一个n,后面有n个字符串,字符串每个字母对应0到25之间的一个数,问你这些字母分别等于多少时候字符串代表的值总和最大(相当于25进制)。而且在字符串不能能有前导0出现。(数值过大对10^9+7取余)
解题思路
不考虑统计没个字符在权位谁高谁低,然后就从25排到0就好了,但是他又要求不能有前导0,所以就必须开个数组标记每个字符是否在大于2的字符串的首位出现,然后在没有出现的字母把权位最低的字母赋值给0,剩下的就又按25到1从到到低排就可以了。
代码部分
#include <iostream>
#include <stdio.h>
#include <cstring>
#include <string>
#include <algorithm>
using namespace std;
const long long int p=1e9+7;
const int maxn=100005;
long long int m[maxn]; //
struct node
{
int vis;
char a[maxn]; ///存每个字符在哪个位子出现的次数用int会出错,下面排序没法排
}num[27];
bool cmd(node a,node b)
{
for(int i=maxn-1;i>0;i--)
{
if(a.a[i]!=b.a[i])
{
return a.a[i]>b.a[i];
}
}
return a.a[0]>b.a[0];
}
void init() ///打每位权重
{
m[0]=1;
long long int ans=26;
for(int i=1;i<maxn;i++)
{
m[i]=ans;
ans=(ans*26)%p;
}
}
int main()
{
int n,T=1; init();
while (scanf("%d",&n)!=EOF)
{
for(int i=0;i<26;i++) ///初始化
{
num[i].vis=0;
for(int j=0;j<maxn;j++) num[i].a[j]=0;
}
for (int i=0;i<n;i++)
{
char c[maxn];
int l;
scanf("%s",&c);
l=strlen(c);
if (l!=1) ///标记是否可以为0
num[c[0]-'a'].vis=1;
for(int j=0;j<l;j++) ///统计没个位上字母出现的次数
{
int x=c[j]-'a';
int y=l-j-1;
num[x].a[y]++;
while(num[x].a[y]==26) //26后要进1,必须用while防止不断进
{
num[x].a[y++]=0;
num[x].a[y]++;
}
}
}
sort(num,num+26,cmd); //把权值高的排在前面
int t;
for (int i=25;i>=0;i--) //从低的开始确认0该给哪个字母
{
if(num[i].vis==0)
{
t=i;
break;
}
}
long long int ans=0;
int k=25;
for (int i=0;i<=25;i++,k--) //计算总和
{
if (i!=t)
for(int j=0;j<maxn;j++)
{
(ans+=(k*m[j]*num[i].a[j]))%=p;
}
else if(i==t)
k++;
}
printf("Case #%d: %lld\n",T++,ans);
}
}