题意:给你n个由小写字母组成的字符串,让你给26个字母分配0-25,每个字符串形成一个26进制的数字,问怎么分
配权值这n个数的和最大。(不能有前导0,但是单个0可以)
官方题解:每个字符对答案的贡献都可以看作一个 26 进制的数字,问题相当于要给这些贡献加一个 0 到 25 的权重使得答案最大。最大的数匹配 25,次大的数匹配 24,依次类推。排序后这样依次贪心即可,唯一注意的是不能出现前导 0。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int mod = 1e9+7;
const int maxn = 1e5+5;
ll fac[maxn] = {1};
int Hash[27];
bool lead[27];
char str[maxn];
void init()
{
for(int i = 1; i < maxn; i++)
fac[i] = fac[i-1]*26%mod;
}
struct node
{
int cnt[maxn];
int id;
bool operator < (const node &a) const
{
for(int i = maxn-1; i >= 0; i--)
{
if(cnt[i] > a.cnt[i]) return 1;
else if(cnt[i] < a.cnt[i]) return 0;
else ;
}
}
}a[27];
int main(void)
{
int n, ca = 1;
init();
while(~scanf("%d", &n))
{
memset(a, 0, sizeof(a));
memset(Hash, -1, sizeof(Hash));
memset(lead, 0, sizeof(lead));
for(int i = 1; i <= n; i++)
{
scanf(" %s", str);
int len = strlen(str);
if(len != 1)
lead[str[0]-'a'] = 1;
for(int i = 0; i < len; i++)
a[str[i]-'a'].cnt[len-i-1]++;
}
//进位操作,满26个等与一个下一位
for(int i = 0; i < 26; i++)
{
for(int j = 0; j < maxn; j++)
{
if(a[i].cnt[j] >= 26)
{
a[i].cnt[j+1] += a[i].cnt[j]/26;
a[i].cnt[j] %= 26;
}
}
a[i].id = i;
}
sort(a, a+26);
for(int i = 0; i < 26; i++)
Hash[a[i].id] = 26-i-1;
for(int i = 0; i < 26; i++) //前导0找最小的可以做0的位来放0
if(lead[a[i].id] && Hash[a[i].id] == 0)
{
for(int j = 25; j >= 0; j--)
{
if(!lead[a[j].id])
{
for(int k = 25; k >= j+1; k--)
Hash[a[k].id] = Hash[a[k-1].id];
Hash[a[j].id] = 0;
break;
}
}
break;
}
ll ans = 0;
for(int i = 0; i < 26; i++)
{
for(int j = 0; j < maxn; j++)
{
ans = (ans+fac[j]*a[i].cnt[j]*Hash[a[i].id]%mod)%mod;
}
}
printf("Case #%d: %lld\n", ca++, ans);
}
return 0;
}