hdu6034-贪心&进制-2017多校1-Balala Power!

39 篇文章 0 订阅

http://acm.hdu.edu.cn/showproblem.php?pid=6034
给定一系列字符串,
给每个字母对应的 0-25映射,要求每个串映射的26进制数最大。每个长度大于1的串开头的字母不能映射为0!

思路:先计算每个字母对应的 权值和(比如a出现在第一个串个数位1次,第二个串十数位1次,权值和就是1+26=27)
但是要注意的一点,直接根据权值和从大到小赋值 25-0,是不可以的。
首先是 有 0赋值的限制条件(0映射的字母不能放在第一个串)。
然后是 权值和 在后来会mod,所以直接比较时不可以的。。
所以还要存一个26进制的数组来模拟比较大小。。
题解的排序方法是很好玩的哈哈

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1000006;
int num[30][maxn];//记录每种字母出现的对应26进制。
bool ban[30];//禁止的数。
int sum[30];//每种元素出现的权值和。
char str[maxn];
int a[maxn];//学习一个,用于排序的。
const int mod=1000000007;
ll wq[maxn];
int l;
bool cmp(int A , int B) {
    for (int i = l -1; i >= 0 ; -- i) {
        if (num[A][i] != num[B][i]) {
            return num[A][i] > num[B][i];
        }
    }
    return 0;
}
void init()
{
     wq[0]=1;
   for(int i=1;i<maxn;i++){
       wq[i]=(wq[i-1]*26)%mod;
       //求位权
       }
}
int w,tt=1;
void solve()
{
            l=0;
          memset(num,0,sizeof(num));
          memset(sum,0,sizeof(sum));
          memset(ban,false,sizeof(ban));
          for(int i=0;i<w;i++){
                scanf("%s",str);
             int len=strlen(str);
             if(len>1)
                 ban[str[0]-'a']=true;
             reverse(str,str+len);
             for(int j=0;j<len;j++){
                sum[str[j]-'a']+=wq[j];
                while(sum[str[j]-'a']>mod)
                    sum[str[j]-'a']-=mod;
                num[str[j]-'a'][j]++;
             }
             l=max(l,len);
          }
         for (int i = 0 ; i < 26 ; ++ i) {
        for (int j = 0 ; j < l ; ++ j) {
            num[i][j + 1] += num[i][j] / 26;
            num[i][j] %= 26;
        }
        while (num[i][l]) {//可能l会变大,这样
            num[i][l + 1] += num[i][l] / 26;
            num[i][l ++] %= 26;
        }
        a[i] = i;
    }

          sort(a,a+26,cmp);
          long long ans=0;
          //弄一弄第一个0;
          int zero=-1;
          for(int i=25;i>=0;i--){
               if(!ban[a[i]])
               {zero=a[i];break;}
          }
          int x=25;
          for(int i=0;i<=25;i++){
                if(a[i]!=zero)
              ans=(ans+(sum[a[i]]*1ll*(x--)))%mod;

          }
           printf("Case #%d: %lld\n",tt++,ans);
}
int main(){
init();
while(~scanf("%d",&w))
solve();

return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值