HDU-6034 Balala Power! - 2017 Multi-University Training Contest - Team 1(贪心)

题意:n串字母,总长度不超过1e6,要求a-z向0-25映射,使字符串对应得到的26进制的数字之和最大。

思路:先计算每个字母在所有串中的贡献,然后通过sort排序贡献和从大到小,然后确定相应的权值,如果所有字母都存在且贡献最小的不能为0即位于某个字符串首位,则寻找第一个能为0的最小的字母将其权值置为0,然后将这些位的权值都向前移一位。


代码:

#include <algorithm>
#include <iostream>
#include <string.h>
#include <cstdio>
#define LL long long
using namespace std;
const LL mod = 1e9+7;
const int maxn = 1e5+15;
const int N = 1e5;
struct node
{
	int val[maxn], key, maxlen;
	bool operator<(const node &k) const
	{
		int len = max(maxlen, k.maxlen)+5;
		for(int i = len; i >= 0; --i)
		{
			if(val[i] == k.val[i]) continue;
			return val[i] > k.val[i];
		}
	}
} lt[30];
int n, real[maxn], mark[30];
LL w[maxn], ans;
char s[maxn];
inline void init()
{
	w[0] = 1;
	for(int i = 1; i <= N; ++i) w[i] = w[i-1]*26%mod;
}
int main()
{
	int count = 0; init();
	while(~scanf("%d", &n))
	{
		memset(mark, 0, sizeof mark);
		for(int i = 0; i < 26; ++i)
		{
			memset(lt[i].val, 0, sizeof lt[i].val);
			lt[i].key = i;
			lt[i].maxlen = 0;
		}
		for(int i = 1; i <= n; ++i)
		{
			scanf("%s", s);
			int len = strlen(s);
			mark[s[0]-'a'] = 1;
			for(int j = 0; j < len; ++j) 
			{
				++lt[s[j]-'a'].val[len-j-1];
				lt[s[j]-'a'].maxlen = max(lt[s[j]-'a'].maxlen, len-j-1);
			} 
		}
		for(int i = 0; i < 26; ++i)
		for(int j = 0; j <= lt[i].maxlen+5; ++j)
		//极端数据100000个长度为10字符串,进位会超出暂时保存的maxlen,多+5即可,因为100000至多除26为3次
		{
			lt[i].val[j+1] += lt[i].val[j]/26;
			lt[i].val[j] %= 26; 
		}
		sort(lt, lt+26);
		for(int i = 25; i >= 0; --i)
		{
			if(i == 25 && mark[lt[i].key])
			{
				int t = i; --i;
				while(mark[lt[i].key])
				{
					real[lt[i].key] = 25-i+1;
					--i;
				}
				real[lt[i].key] = 0;
				real[lt[t].key] = 1;
			}
			else 
			real[lt[i].key] = 25-i;
		}
		ans = 0;
		for(int i = 0; i < 26; ++i)
		{
			for(int j = 0; j <= lt[i].maxlen+5; ++j)
			ans = (ans+real[lt[i].key]*w[j]%mod*lt[i].val[j]%mod)%mod;
		}
		printf("Case #%d: %lld\n", ++count, ans);
	}
	return 0;
} 


继续加油~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值