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, 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, 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;///如果该字母在第一位,则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; } |