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

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.  (1n100000)

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

char str[N];
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;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值