【HDU6034】Balala Power!

记录一个菜逼的成长。。

2017 Multi-University Training Contest - Team 1

题目链接
题目大意:
给你n个小写的字符串。
给每种小写字母赋值,每个字符串就相当于一个数,使得最后的和最大。

考虑每种字母的贡献,
如果一个字母贡献大,那么这个字母必然出现在高位且次数多。
根据这个规则排序
对次数考虑进位,可以使常数变小。
再考虑不能给出现过字符串头的字母赋值 0 <script type="math/tex" id="MathJax-Element-4">0</script>。

#include <bits/stdc++.h>
using namespace std;
#define rep(i,l,r) for( int i = l; i <= r; i++ )
#define rep0(i,l,r) for( int i = l; i < r; i++ )
#define ALL(v) (v).begin(),(v).end()
#define cl(a,b) memset(a,b,sizeof(a))
#define clr clear()
#define pb push_back
#define mp make_pair
#define fi first
#define se second
typedef long long LL;
typedef pair<int,int> PII;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9+7;
const int maxn = 100000 + 10;
int cnt[27][maxn],head[27],a[27],mxlen;
LL Power[maxn],sum[27];
char str[maxn];
bool cmp(int a,int b)
{
  for( int i = mxlen-1; i >= 0; i-- ){
    if(cnt[a][i] != cnt[b][i])
      return cnt[a][i] < cnt[b][i];
  }
  return 0;
}
int main()
{
  Power[0] = 1;
  for( int i = 1; i < maxn; i++ ){
    Power[i] = Power[i-1] * 26 % MOD;
  }
  int n,cas = 1;
  while(~scanf("%d",&n)){
    cl(cnt,0);cl(sum,0);cl(head,0);
    mxlen = 0;
    for( int i = 1; i <= n; i++ ){
      scanf("%s",str);
      int len = strlen(str);
      if(len > 1)head[str[0]-'a'] = 1;
      mxlen = max(mxlen,len);
      for( int j = len-1; j >= 0; j-- ){
        cnt[str[j]-'a'][len-j-1] ++;
        sum[str[j]-'a'] += Power[len-j-1];//预处理假设所有字母值为1,最后只要乘上给每种字母的权值即可
        if(sum[str[j]-'a'] >= MOD)sum[str[j]-'a'] -= MOD;
      }
    }
    //对次数进位,减小常数
    for( int i = 0; i < 26; i++ ){
      for( int j = 0; j < mxlen; j++ ){
        cnt[i][j+1] += cnt[i][j] / 26;
        cnt[i][j] %= 26;
      }
      while(cnt[i][mxlen]){
        cnt[i][mxlen+1] += cnt[i][mxlen] / 26;
        cnt[i][mxlen++] %= 26;
      }
      a[i] = i;
    }

    sort(a,a+26,cmp);
    int zero = -1;
    //在字符串头部出现过的字母不能赋值0,从小往大遍历,找到可以赋值0,且贡献最小的字母
    for( int i = 0; i < 26; i++ )
      if(!head[a[i]]){zero = a[i];break;}
    LL ans = 0;
    for( int x = 25,i = 25; i >= 0; i-- ){
      if(a[i] != zero){
        ans = (ans + (LL)x-- * sum[a[i]]) % MOD;
      }
    }
    printf("Case #%d: %lld\n",cas++,ans);
  }
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值