2017 Multi-University Training Contest - Team 1 - 1002

Balala Power!
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 4455 Accepted Submission(s): 1107

Problem Description

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.

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

Output
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.

Sample Input

1
a
2
aa
bb
3
a
ba
abc

Sample Output

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

题目连接
题目大意:给你一些字符串(a~z)要求你赋给它们0~25按照26进制计算使得所有字符串的总和最大。如果字符串的长度大于1那么字符串的第一个字符不能为0.
解释样例:1.令a=25,25*26^0=25.2.a=25,b=24,sum=25*26^0+25*26^1+24*26^0+24*26^1=1323
3.a=25,b=24,c=23 sum=25+25*26^0+24*26^1+25*26^2+24*26^1+23*26^0=18221.
解题思路:这其实就是一个模拟题计算多个26进制数相加。
1.开一个二维数组统计每一个字符在每一位的个数,如果这个字符在这一位的数量大于了26则前一位这个字符的数量加上这一位该字符的数量的除数。并把前一位取余数。3.给每一个字符赋相应的数字(0~25)写一个自定义的函数放在sort排序里面 具体的逻辑是比较所有的字符在最高位的个数这样就能使总和最大(因为前面已经进行了一步进位操作,这样就能保证最大)3.解决前导零的问题,如果所有的字符都出现那么只要是字符串大于1则最前面的一位字符就不能做为0具体操作是每当输入一个字符串时如果这个字符串的长度大于1那么就标记第一个字符用一个标记数组即可,输入完所有的字符串之后进行一个for循环注意这时候就是已经排序完的字符串数组了,当遇到没有被标记的字符时说明这个字符可以作为0即给其做一个标记,当遍历进行计算是就不对这个字符所代表的字符进行计算了。这样就能求出最后的结果了。
AC代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;

const int N = 100020;
const int Q = 1e9 + 7;
int n, L;
int num[26][N];///二维数组用来存储每一个字母在每一位的个数
int power[N], sum[N]; ///分别表示26的n次方的表格便于计算时间复杂度也小和每一位的位权
bool ban[26];///标记数组,即如果该字符出现则标记为1便于为字符赋值

char str[N];///表示字符串数组
int a[26];///字母数组,用数字表示

bool cmp(int A, int B)  ///sort函数里的比较规则返回在这一位较多的那个字符
{
    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)
        {
            ban[str[0] - 'a'] = 1;///开头字符标记为1,不能作为前导0
        }
        reverse(str, str + len);///将字符串翻转
        for (int j = 0 ; j < len ; ++ j)
        {
            ++ num[str[j] - 'a'][j];///第j位的该字符数量增加
            sum[str[j] - 'a'] += power[j];///该字符在所有该位上的位权
            if (sum[str[j] - 'a'] >= Q)///如果大于模数Q则减去一个Q因为一步只加一个所以不可能多出两个Q
            {
                sum[str[j] - 'a'] -= Q;///这里换成%也是正确的
            }
        }
        L = max(L, len);///将输入的最长的字符串的长度赋给L
    }
    for (int i = 0 ; i < 26 ; ++ i)
    {
        for (int j = 0 ; j < L ; ++ j)
        {
            num[i][j + 1] += num[i][j] / 26;///如果该位的字符个数大于26则向前进位
            num[i][j] %= 26;
        }
        while (num[i][L])///如果该字符串为最长的字符串对第一位进行同样的操作
        {
            num[i][L + 1] += num[i][L] / 26;
            num[i][L ++] %= 26;
        }
        a[i] = i;///每个字符所对应的数字
    }
    sort(a, a + 26, cmp);///对每一个字符进行一个升序排序,出现次数最多的赋25然后依次向下
    int zero = -1;
    for (int i = 0 ; i < 26 ; ++ i)///寻找第一个可以作为零的那个字符(从小向大进行,保证可以作为前导零的为最小使结果最大)
    {
        if (!ban[a[i]])///第一个能作为前导零的字符
        {
            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;///按照sum最大的字符从25向后进行计算这样保证算出来的结果最大
            res %= Q;
        }
    }
    static int ca = 0;
    printf("Case #%d: %d\n", ++ ca, res);
}

int main()
{

    power[0] = 1;
    for (int i = 1 ; i < N ; ++ i)
    {
        power[i] = (LL)power[i - 1] * 26 % Q;
    }
    while (~scanf("%d", &n))
    {
        work();
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值