2017 Multi-University Training Contest 1 && HDOJ 6034 Balala Power! 【贪心】


Balala Power!

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit:131072/131072 K (Java/Others)
Total Submission(s): 916    Accepted Submission(s): 153

Problem Description

 


Talented Mr.Tang hasn strings consisting of only lower case characters. He wants to charge them with Balala Power (he could change each character ranged froma toz into each number ranged from0 to25, but each two different characters should not be changed into the same number) so that he could calculate the sum of these strings as integers in base 26 hilariously.

Mr.Tang wants you to maximize the summation. Notice that no string in this problem could have leading zeros except for string "0". It is guaranteed that at least one character does not appear at the beginning of anystring.

The summation may be quite large, so you should output it in modulo 109+7.

 

 

Input

The input contains multiple test cases.

For each test case, the first line contains one positive integers
n, the number of strings. (1≤n≤100000)

Each of the next
n lines contains a stringsi consisting ofonly lower case letters. (1≤|si|≤100000,∑|si|≤106)

 

 

Output

For each test case, output "Case #x:y"in one line (without quotes), wherex indicates thecase number starting from 1 andy denotes the answer of corresponding case.

 

 

Sample Input

1

a

2

aa

bb

3

a

ba

abc

 

 

Sample Output

Case #1: 25

Case #2: 1323

Case #3: 18221


【题意】给出n个由小写字母组成的字符串,你可以对每个字符赋值,范围为0~25,但每个权值只能用一次,且赋值后数字不能有前导零(可以是单个零),然后构成了n个26进制数,问n个数的最大和为多少?


【思路】显然我们应该对位置靠前的字母赋以更大的权值,那么我们首先要做的是,统计出每个字母在哪一位出现了几次,然后比较每个字母取能对结果产生的贡献大小。比赛时有点傻,没办法用大数直接暴力算出每个字母贡献的大小,然后排序,果断超时。


比完后才知道我们可以这样来比较,每个字母从最后一位开始,如果个数大于等于26,则向前进位,以此类推,最终只要从最高位的个数开始比较即可。

然后按贡献从大到小对字母依次用25——0赋值,上面的这个结论是错误的,没有考虑前导零,在读入的时候应用vis数组保存不能赋值为0的字母编号,然后排序后选贡献最小且满足条件的的赋值为0,其他就按贪心赋值,就可以算出结果。


其他细节见代码。

#include <cstdio>
#include <cmath>
#include <vector>
#include <iostream>
#include <set>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;
#define mst(a,b) memset((a),(b),sizeof(a))
#define rush() int T;scanf("%d",&T);while(T--)

typedef long long ll;
const int maxn = 100005;
const ll mod = 1e9+7;
const int INF = 0x3f3f3f;
const double eps = 1e-9;

int n;
char s[maxn];
int num[26][maxn];
int vis[26];
int val[maxn];
ll po[maxn];
int Max;

struct node
{
    char xx[maxn];
    int id;
}e[26];

bool cmp(const node &a,const node &b)  //对贡献从大到小排序
{
    for(int i=Max-1; i>=0; i--)
    {
        if(a.xx[i]>b.xx[i])
            return 1;
        if(a.xx[i]<b.xx[i])
            return 0;
    }
    return 1;
}

void init()                 //预处理26^n%mod
{
    po[0]=1;
    for(int i=1; i<maxn; i++)
    {
        po[i]=(po[i-1]*26)%mod;
    }
}

int main()
{
    int n;
    int cas=1;
    init();
    while(~scanf("%d",&n))
    {
        mst(num,0);
        mst(vis,0);
        mst(val,0);
        for(int i=0; i<n; i++)
        {
            scanf("%s",s);
            int len=strlen(s);
            if(len>1)                     //标记这个字母权值不能为零
            {
                vis[s[0]-'a']=1;
            }
            for(int j=len-1; j>=0; j--)   //统计每个字母在第几位上有几个
            {
                int o=len-1-j;
                num[s[j]-'a'][o]++;
            }
            Max=max(Max,len);             //减少循环,节约时间
        }
        for(int i=0; i<26; i++)
        {
            for(int j=0; j<maxn; j++)
            {
                if(num[i][j]>=26&&j!=Max-1)
                {
                    num[i][j+1]+=num[i][j]/26;
                    num[i][j]%=26;
                }
            }
        }
        for(int i=0; i<26; i++)
        {
            for(int j=0; j<Max; j++)
            {
                e[i].xx[j]=num[i][j]+'a';  //转化为字符形式,节约内存,如果是int可能会爆内存
            }
            e[i].id=i;
        }
        sort(e,e+26,cmp);
        int pos=-1;
        for(int i=25;i>=0;i--)           //从权值小的开始找权值可以为0的字母
        {
            if(vis[e[i].id]==0)
            {
                pos=e[i].id;
                break;
            }
        }
        int flag=0;
        for(int i=0;i<26;i++)             //给每个字母附上权值
        {
            if(e[i].id==pos)
            {
                val[e[i].id]=0;
                flag=1;
                continue;
            }
            if(flag==0) val[e[i].id]=25-i;
            else val[e[i].id]=25-i+1;
        }
        ll ans=0;
        for(int i=0;i<26;i++)
        {
            for(int j=0;j<Max;j++)
            {
                if(num[i][j])
                {
                    ll temp=(ll)num[i][j]*val[i]*po[j]%mod;
                    ans=(ans+temp)%mod;
                }
            }
        }
        printf("Case #%d: %I64d\n",cas++,ans);
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值