2017多校 Balala Power!

当时比赛这个题,wa了次,最后发现思路是有一点问题。今天补题,也是出现了很多错误,哎,还是太菜了,必须要多写代码。

题意:将a-z这26个字母用0-25进行赋值。那么对于一个字符串,就可以看作是一个26进制,那么该字符串就可以转化为一个10进制的数,求所有字符串的和的最大值。(如果一个字母被赋值为0,那么该字母不能出现在首位。a这种是可以的)

比赛时候的思路是:我把每一个位赋初值0,100000,200000....这种。每个字母出现在每一位的时候就++,然后把所有字母的和相加,可以对这些字母进行排序。

后来想的是通过用num[26][100010],表示该字母在这一位上的个数,如果数量超过26,就进位。

代码如下:

//高精度的思想求每个字母的权值 
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
ll num[28][100050];
ll high[27],alph[27],lead[27],weight[27];//high记录每个字母的最高位是第几位,alph记录字母的权值大小,从大到小,lead记录前导零,weight记录权值 
bool cmp(ll a,ll b)
{
if(high[a]==high[b])
{
for(ll j=high[a];j>=0;j--)
{
if(num[a][j]!=num[b][j])
  return num[a][j]>num[b][j];
}
}
else
 return high[a]>high[b];
}
long long pow(long long a,long long x)//以防万一,这里以后都要有long long 
{
long long res=1;
while(x)
{
if(x&1)
 res=(res*a)%mod;
a=(a*a)%mod;
x>>=1;
}
return res%mod;
}
int main()
{
    ll n,kase=1;
    while(~scanf("%lld",&n))
    {
    char s[100010];
    ll lenn=-1;
    memset(num,0,sizeof(num));
    memset(lead,0,sizeof(lead));
    memset(high,0,sizeof(high));
        for(int i=0;i<n;i++)
        {
        scanf("%s",&s);
   ll len=strlen(s);
   if(len!=1)
     lead[s[0]-'a']=1;
   for(ll j=len-1;j>=0;j--)
   {
    num[s[j]-'a'][len-j]++;
    if(num[s[j]-'a'][len-j]>=26)//1是最低位 
    {
    num[s[j]-'a'][len-j+1]+=num[s[j]-'a'][len-j]/26;
    num[s[j]-'a'][len-j]=num[s[j]-'a'][len-j]%26;
}
}
lenn=max(lenn,len);
}
for(ll i=0;i<26;i++)
{
for(ll j=1;j<lenn+10;j++)
{
if(num[i][j])
  high[i]=j;//记录每个字母的最高位 
num[i][j+1]+=num[i][j]/26;
num[i][j]=num[i][j]%26;
}

for(ll i=0;i<26;i++)
 alph[i]=i;
sort(alph,alph+26,cmp);
int k=25;
for(int i=0;i<26;i++)
  weight[alph[i]]=k--;
   if(weight[alph[25]]==0&&lead[alph[25]])//如果权值最小的那个字母是首字母 
   {
    for(int i=24;i>=0;i--)
    {
    if(lead[alph[i]]==0)
    {
    for(int j=25;j>=i;j--)
    {
    weight[alph[j]]=weight[alph[j-1]];
}
weight[alph[i]]=0;
break;
}
}
}
long long ans=0;
for(ll i=0;i<26;i++)
{
for(ll j=1;j<lenn+26;j++)
{
ans+=((long long)(pow(26,j-1)*weight[i])%mod*num[i][j])%mod;
ans=ans%mod;
}
}
printf("Case #%lld: %lld\n",kase++,ans);
}
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值