hdu-6034-Balala Power!


 Balala Power!

时间限制: 4 Sec   内存限制: 128 MB

题目描述

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.

样例输入

1
a
2
aa
bb
3
a
ba
abc

样例输出

Case #1: 25
Case #2: 1323
Case #3: 18221
题意:给出 n个字符串,字符包括 a~z,分别给它们赋值 0~25,使得这些串表达成26进制时的和最大
官方题解:每个字符对答案的贡献都可以看作一个 26 进制的数字,问题相当于要给这些贡献加一个 0 到 25 的权重使得答案最大。最大的数                    匹配 25,次大的数匹配 24,依次类推。排序后这样依次贪心即可,唯一注意的是不能出现前导 0。
思路:用二维数组num[ ] [ ],记录每个字母在哪一位出现了多少次,即num[字母] [出现的位数]=字母在位数出现的次数,另外用sum[ ]数组存储             字母的“贡献”,即sum[字母]=该字母的贡献,另外开一个数组ban[ ],来处理前导零问题,各个字符串统计好之后,根据每个字母的贡献              对字母进行排序(用num数组而不用sum数组),按着贪心思想,给字母分配权重,得出答案;
代码:
 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#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];           ///num[字母][该字母在的位数]=字母在该位出现的次数
int power[N], sum[N];     ///sum[字母]=该字母目前的贡献,pow[位数]=该位的贡献(26^x);
bool ban[ 26];             ///处理前导零

char str[N];
int a[ 26];

///根据在每位出现的次数进行排序,因为位数高的占的权重比较大,
///所以先从高位开始,按权重从小到大排序
bool cmp( int A,  int B)
{
     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,  0sizeof(num));
    memset(ban,  0sizeof(ban));
    memset(sum,  0sizeof(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; ///如果该字母在第一位,则ban[**]=1;
        }

        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)

                sum[str[j] -  'a'] =  sum[str[j] -  'a']%Q;
        }

        L = max(L, len);
    }


     ///对每个字母出现的次数进行进位处理,(以26进制)
     for ( int i =  0 ; i <  26 ; ++ i)
    {
         for ( int j =  0 ; j < L ; ++ j)
        {
            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;
    }
     ///排序
    sort(a, a +  26, cmp);
     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;
            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;   ///power[i]=26^i;
    }
     while (~scanf( "%d", &n))
    {
        work();
    }
     return  0;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值