hdu6034--贪心

思路:算出每一个字母的贡献值,然后按贡献值由小到大赋值0到25,注意要记录那些字母若为0,则出现前置0,如何算贡献值?

记录每一个字母在第几位出现几次,得出一个26进制数,以这个26进制数作为贡献值

#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
using namespace std;
const int N = 1e5+10;
const int mod = 1e9+7;
typedef long long ll;
struct node{
	int len[N];//贡献值(是一个26进制数)
	int w;//代表的字母
	int v;// 代表的数字
	int L;//贡献值的长度 
}p[26];
bool cmp(node a,node b){
	if(a.L != b.L) return a.L < b.L;
	for(int i = a.L;i >= 0;i--){
		if(a.len[i]==b.len[i]) continue;
		return a.len[i]<b.len[i];
	}
	return 0;//这个一定要加否则两者一样时无法比较 
}
bool flag[26];
int n;
string str[N];
int main(){
	int cas = 1;
	while(~scanf("%d",&n)){
		memset(flag,0,sizeof(flag));
		for(int i = 0;i < 26;i++){
			for(int j = 0;j <= p[i].L;j++){
				p[i].len[j]=0;
			}
		}
		for(int i = 0;i < 26;i++){
			p[i].L=-1;//表示它没有出现过
			p[i].v = 0;
			p[i].w = i; 
		}
		for(int i = 0;i < n;i++){
			cin>>str[i];
			if(str[i].size()>1) flag[str[i][0]-'a'] = 1;//若这个字母为0,则出现前置0
			reverse(str[i].begin(),str[i].end());
			for(int j = 0;j < str[i].size();j++){
				p[str[i][j]-'a'].len[j]++;
			} 
		}
		//进位处理
		for(int i = 0;i < 26;i++){
			for(int j = 0;j < N;j++){
				if(p[i].len[j]>=26){
					int d = p[i].len[j]/26;
					p[i].len[j]%=26;
					p[i].len[j+1]+=d;
				}
				if(p[i].len[j]>0) p[i].L = max(p[i].L,j);
			}
		} 
		sort(p,p+26,cmp);
		//根据贡献值从小到大赋予字母数字 
		for(int i = 0;i < 26;i++){
			p[i].v = i;
		}
		//如果有字母为0会造成前置0,则比它贡献值大一位的字母当0 
		for(int i = 0;i < 26;i++){
			if(flag[p[i].w]&&p[i].v==0){
				swap(p[i].v,p[i+1].v);
			}
		}
		ll ans = 0;
		ll value[26];//由字母直接指向数字
		for(int i = 0;i < 26;i++){
			value[p[i].w]=p[i].v;
		} 
		for(int i = 0;i < n;i++){
			ll now = 1;
			for(int j = 0;j < str[i].size();j++){
				ans = (ans+(value[str[i][j]-'a']*now)%mod)%mod;
				now = (now*26)%mod;
			}
		}
		printf("Case #%d: %lld\n",cas++,ans);
	}
	return 0;
} 
发布了27 篇原创文章 · 获赞 0 · 访问量 346

猜你喜欢

转载自blog.csdn.net/weixin_44083561/article/details/104110456