HDU 2017 多校联赛 1002 Balala Power!

题目描述

Talented Mr.Tang has n strings consisting of only lower case characters. He wants to charge them with Balala Power (he could change each character ranged from a to z into each number ranged from 0 to 25, 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 any string.

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


输入

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 string si consisting of only lower case letters. (1≤|si|≤100000,∑|si|≤106)

输出

For each test case, output “Case #x: y” in one line (without quotes), where x indicates the case number starting from 1 and y denotes the answer of corresponding case.

样例输入




aa 
bb 


ba 
abc

样例输出

Case #1: 25 
Case #2: 1323 
Case #3: 18221

题目大意:

输入一个数n,接下来有n行字符串,只有从‘a’到‘z’,向这些字符随机赋值从0到25,每个数只能使用一次,开头字符不可为0。字符串为26进制,求n个字符串相加的最大值。每个字符对答案的贡献都可以看作一个 26 进制的数字,问题相当于要给这些贡献加一个 0 到 25 的权重使得答案最大。最大的数匹配 25,次大的数匹配 24,依次类推。排序后这样依次贪心即可,唯一注意的是不能出现前导 0。

c++

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long LL;   // 用LL来替换long long
const int N = 100020;
const int Q = 1e9 + 7;
int n , L;
int num[26][N];       //sum一维下标存该字母减去‘a’的ASCLL码,也就是该字母元素
//二维数组下标存该字母元素的位置,数组里存该字母元素出现的个数
int power[N] , sum[N];    //power数组存对应位的权值,sum数组存相同字母对应位的权值总和
bool ban[26];      //作为标记数组,将出现在开头的字母作标记
char str[N];
int a[26];       //用来映射每个字母所代表的值
bool cmp(int A , int B)     //排序依据是num存的字母从高位到低位个数的多少
{
    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 work() {
    memset(num , 0 , sizeof(num));
    memset(ban , 0 , sizeof(ban));
    memset(sum , 0 , sizeof(sum));
    L = 0;
    for (int i = 0 ; i < n ; ++ i)
    {
        scanf("%s" , str);
        int len = strlen(str);
        if (len > 1)        //如果字符串长度大于1,则标记该字符串首字母不能为0
        {
            ban[str[0] - 'a'] = 1;
        }
        reverse(str , str + len);     //将字符串str倒置
        for (int j = 0 ; j < len ; ++ j)
        {
            ++ num[str[j] - 'a'][j];     //存字母出现的次数
            sum[str[j] - 'a'] += power[j];      //求出现的字母的所有权值
            if (sum[str[j] - 'a'] >= Q)      //如果sum里的数超过了Q,则对它取余
            {
                sum[str[j] - 'a'] -= Q;
            }
        }
        L = max(L , len);      //保存输入字符串的最大长度
    }
    for (int i = 0 ; i < 26 ; ++ i)
    {
        for (int j = 0 ; j < L ; ++ j)
        {
            //处理元素i个数的进位情况
            num[i][j + 1] += num[i][j] / 26;
            num[i][j] %= 26;
        }
        while (num[i][L])      //进位后位数可能会有变化;
        {
            num[i][L + 1] += num[i][L] / 26;
            num[i][L ++] %= 26;
        }
        a[i] = i;    //对a数组进行赋初值
    }
    sort(a , a + 26 , cmp);      //对a数组排序,排序后a数组内容代表字母,下标代表字母所代表
    int zero = -1;
    for (int i = 0 ; i < 26 ; ++ i )
    {
        if (!ban[a[i]])     //找到最小的可以为0的字母
        {
            zero = a[i];
            break;
        }
    }
    int res = 0 , x = 25;
    for (int i = 25 ; i >= 0 ; -- i)
    {
        if (a[i] != zero)      //如果不是单个字母就开始统计所有的加和值
        {
            res += (LL)(x --) * sum[a[i]] % Q;
            res %= Q;
        }
    }
    static int ca = 0;
    printf("Case #%d: %d\n" , ++ ca , res);
}

int main() {
    power[0] = 1;          //初始化power数组,个位的权值为26^0=1
    for (int i = 1 ; i < N ; ++ i) {
            //依次用低一位的权值*26得到高一位的权值,然后对10^9+7取模
        power[i] = (LL)power[i - 1] * 26 % Q;
    }
    while (~scanf("%d" , &n)) {
        work();
    }
    return 0;
}




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值