您的位置:首页 > 其它

2017 杭电多校联赛 1002 Balala Power!(数字替换字母)HDU 6034

2017-07-26 15:00 447 查看


Balala Power!

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)

Total Submission(s): 4809    Accepted Submission(s): 387


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 froma 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

 题目大意:

给你n个由小写字母组成的字符串,每个相同的字母都可以由0~25中的任意一个数字取代,求取代后的字符串变成的26进制转换成十进制最大是多少。

解题思路:

1、ans = 出现的所有字母转换后的值的和

每一个字母在最终答案里的值都是由多个26的倍数相加后乘以那个字母代表的数

eg:

字符串1:abc  c = 替换 c 的值 * 26 ^0

字符串2:cba  c = 替换 c 的值 * 26 ^2

最终c 的值 = 替换 c 的值*(26 ^0 +26 ^2)

因为替换c 的值还未定,所以可以先把后面的部分算出来

2、因为不能有前导零,所以要标记哪些字母不能赋值为0,同时要找出最终赋值为0的字母使得最终的结果最大

3、具体的代码中有标注释

代码

#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]
;//dp[c-'a'][i]储存字母 c 在i位有多少个
int power
, sum
;//sum[c-'a']表示替代字母c 的值要乘的后面的部分
bool ban[26];

char str
;
int a[26];//a[i]=c-'a' 表示字母 c 在所有字母中占的部分大小是倒数第 i 位 占的部分越大说明替换这个字母的值要越大

bool cmp(int A , int B) {
for (int i = L - 1 ; i >= 0 ; -- i) {
//printf("num[%d][%d]=%d  num[%d][%d]=%d\n",A,i,B,i,num[A][i],num[B][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;//如果这个字母变成 0 会造成前导零的存在则 ban[c-'a']=1
}
reverse(str , str + len);//将这个字符串倒过来
for (int j = 0 ; j < len ; ++ j) {
++ num[str[j] - 'a'][j];
sum[str[j] - 'a'] += power[j];//计算字母str[j]替代后所乘的数
if (sum[str[j] - 'a'] >= Q) {
sum[str[j] - 'a'] -= Q;
}
}
L = max(L , len);
}
//如果字母 c 在 i位置上有26个,那么它所乘的数是26^i *26 == 26^(i+1)
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;
}
/*for(int i=0;i<26;i++){
for(int j=0;j<L;j++){
printf("num[%c][%d]=%d\n",i+'a',j,num[i][j]);
}
}*/
sort(a , a + 26 , cmp);//将a[]按照所占部分大小从小到大排序
int zero = -1;//zero=c-'a' 表示最终赋值为 0 的字母
//从所占位置最小的部分开始寻找有没有可以赋值为0而不造成前导0的数字母
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) {//如果a[i]这个字母不是赋值为0的字母,结果则加上它所占的部分
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;
}
while (~scanf("%d" , &n)) {
work();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息