hdu6034-贪心

题意:给a-z字符赋上0-25每个数字只能赋一次求怎么赋值使得数值最大然后取膜1e9+7
题解:给拥有最大位数并且最大位数的拥有个数最多的赋值最大然后依次递减记得处理前导不能为0的情况

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long int ll;
const int mx = 1e5+5;
const int L = 1e5;
const ll mod = 1e9+7;
char s[mx];
ll x[mx];
struct node{
    int num[mx],low,date;
    bool operator<(const node &a)const{
        for(int i = 1; i < L; i++)
            if(num[i]!=a.num[i])
            return num[i]>a.num[i];
        return num[L]>a.num[L];
    }
}a[30];
bool vis[30],mark[30];
int main(){
    x[L] = 1;
    for(int i = L-1; i >= 1; i--)
        x[i] = x[i+1]*26%mod;
    int casei = 1,n;
    while(scanf("%d",&n)!=EOF){
        for(int i = 0; i < 26; i++){
            vis[i] = 0;
            mark[i] = 0;
            a[i].low = i;
            memset(a[i].num,0,sizeof(a[i].num));
        }
        for(int i = 1; i <= n; i++){
            scanf("%s",s+1);
            int len = strlen(s+1);
            vis[s[1]-'a'] = 1;
            for(int j = 1; j <= len; j++){
                a[s[j]-'a'].num[L-(len-j)]++;
                mark[s[j]-'a'] = 1;
            }
        }
        int cnt = 0;
        for(int i = 0; i < 26; i++){
            if(mark[i])
                cnt++;
            for(int j = L; j >= 2; j--){
                a[i].num[j-1] += a[i].num[j]/26;
                a[i].num[j] %= 26;
            }
        }
        sort(a,a+26);
        if(cnt == 26){ //如果26个字母都出现过
            if(vis[a[25].low]){   //判断是否最后一个前导为0
                int p;
                for(int i = 25; i >= 0; i--)
                    if(!vis[a[i].low]){
                        p = i;              //找到第一个不是前导的位置
                        break;
                    }
                for(int i = 0; i < 26; i++) //从上到下依次递减赋值
                    if(i!=p)              
                        a[i].date = --cnt;   
                    else
                        a[i].date = 0;     //排序完最小的不是前导的赋值为0
            }
            else
                for(int i = 0; i < 26; i++)
                    a[i].date = 25-i;
        }
        else
            for(int i = 0; i < 26; i++)
                a[i].date = 25-i;
        ll ans = 0;
        for(int i = 0; i  < 26; i++)if(mark[a[i].low]){  //判断一下有没有这个字母
            for(int j = 1; j <= L; j++)
                if(a[i].num[j])  //如果这个位数有数值再进行运算减少不必要的时间
                    ans = (ans+a[i].num[j]*a[i].date*x[j])%mod;

        }
        ans%=mod;
        printf("Case #%d: %I64d\n",casei++,ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值