HDU6034-Balala Power! 贪心

传送门

题意:

n个字符串,a-z自定义映射为0-25,每个字符串看做一个26进制数,在限制条件下,求n个数和的最大值。

思路:

1、存下每一种字母(26种,容量为26的结构体数组)在每一位出现的次数(100000位,结构体内容量为100000的int数组),方便比较每一位都要符合26进制,然后从低到高进行排序(贪心);

2、但是要注意,题目虽然说一定有一个字母没有出现在最高位过,保证了一定存在合法的映射,(合法即不能出现前导零),但是排序后的序列可能将出现在最高位过的字母排到最后一位,赋值为0就非法了。所以这种情况需要特判,然后从后往前找第一个没出现在最高位的字母替换到最后,前面依次迁移

#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define N 100005
#define M 105
#define INF 0x3f3f3f3f
#define mod 1000000007
char s[N];
LL all[N];   // all[i] 表示 26的i次方对 mod 取膜 后剩下的数
bool has[26];
struct node
{
    int index;
    int num[N];  //表示每一位的数字
    bool friend operator <(node x,node y){
       for(int i=N-1;i>=0;i--){
        if(x.num[i]!=y.num[i]) return x.num[i] < y.num[i];   
       }
       return 0;
    }
}no[26];   
int main()
{
    all[0] = 1;
    for(int i=1;i<N;i++) all[i] = all[i-1] * 26 % mod;  //预处理 26 
    int n;
    int cas = 1;
    while(~scanf("%d",&n)){
     memset(has,0,sizeof(has));
     for(int i=0;i<26;i++){
     memset(no[i].num,0,sizeof(no[i].num));
     no[i].index = i;
     }
     while(n--){
       scanf("%s",s);
       has[s[0]-'a'] = 1;         //标记,在首位出现过
       int len = strlen(s);
       for(int i=0;i<len;i++){
          no[s[i]-'a'].num[len-1-i]++;
       }
     }
     int zero;   
     for(int i=0;i<26;i++){      //进位,便于比较
        int yu = 0;
        for(int j=0;j<N;j++){
           int w = yu;
           yu = (yu + no[i].num[j]) / 26;
           no[i].num[j] = (no[i].num[j] + w) % 26;
        }
     }
     sort(no,no+26);
     for(int i=0;i<26;i++){
        if(!has[no[i].index]){   //找最小的,未在首位出现的数,置为0
            zero = i;
            break;
        }
     }
     LL ans = 0;
     for(int i=25;i>=0;i--){
        LL No;
        if(i==zero) continue;    //为0,跳过
        else if(i > zero) No = i;
        else  No = i + 1;        //在为0的数后面,则进一位
        for(int j=0;j<N;j++){
            if(!no[i].num[j]) continue;
            ans = (ans + all[j] * no[i].num[j] * No) % mod;
        }
     }
     printf("Case #%d: %lld\n",cas++,ans);
    }
}


  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值