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

http://acm.hdu.edu.cn/showproblem.php?pid=6034

题意:

有一个仅由小写字母组成的字符串,要求将a..z的字母,对应到0..25,每个数字只能被一个字母对应,得到一个26进制的数,现在问这个数最大是多少。注意不允许有前导0,除非这个数本身就是0.

思路:

贪心。看哪个字母的权值最大。

可以用类似高精度加法的方式处理。

对于前导0的部分,用一个bool标记首位(如果字符串长度为1就不标记)

对于26个高精度数的排序,可以用交换id的技巧。

以及,如果排序之后,发现权值最小的数被对应到数字0,但是又在某个长度大于1的字符串的首字母位置出现过。

我初始想当然得,把该字母和最小的可以出现在首位的字母交换....

然而这很错啊?

实际上,更优秀做法是,找到第一个可以出现在首位的字母,然后从该字母后面到结尾,依次前移一位,最后把这个可以出现在首位的字母放在最后。

比如这组数据:

7 abcdefghijklmnopqrstuvwxyz zz yy xx ww uu vv

权值按照从大到小排列

z u v w x y t 显然不如  u v w x y z t  优

/* ***********************************************
Author :111qqz
Created Time :2017年11月01日 星期三 00时56分26秒
File Name :6034.cpp
************************************************ */

#include <bits/stdc++.h>
#define PB push_back
#define fst first
#define sec second
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define ms(a,x) memset(a,x,sizeof(a))
typedef long long LL;
#define pi pair < int ,int >
#define MP make_pair

using namespace std;
const double eps = 1E-8;
const int dx4[4]={1,0,0,-1};
const int dy4[4]={0,-1,1,0};
const int inf = 0x3f3f3f3f;
const int N=1E5+7;
const LL mod =1E9+7;
int n;
string st[N];
int cnt[26][N];
int maxlen;
int id[26];
int power[26];
LL base26[N];
bool Beg[26];
void init()
{
    ms(Beg,false);
    ms(cnt,0);
    maxlen = 0 ;
    for ( int i = 0 ; i < 26 ; i++) id[i] = i;
}
bool small(int *a,int *b)
{
    for ( int i = maxlen-1 ; i >= 0 ; i--)
    {
    if (a[i]<b[i]) return true;
    if (a[i]>b[i]) return false;
    }
    return false;
}
int main()
{
    #ifndef  ONLINE_JUDGE 
    freopen("./in.txt","r",stdin);
  #endif
    int cas = 0 ;
    base26[0] = 1;
    for ( int i = 1 ; i < N ; i++) base26[i] = base26[i-1] * 26 % mod; 
    while (~scanf("%d",&n))
    {
        init();
        for ( int i = 1 ; i <= n ; i++) 
        {
        cin>>st[i];
        int len = st[i].length();
    //  cout<<"len:"<<len<<endl;
        maxlen = max(len,maxlen);
        for ( int j = 0 ; j < len ; j++)
        {
            int v = st[i][j]-'a';
            cnt[v][len-j-1]++;
        }
        //如果只有一个字母,不要打首字母标记
        if (len>1)
        Beg[st[i][0]-'a'] = true;
        //忘了不能右前导0的条件了。。。
        }
        for ( int i = 0 ; i < 26 ; i++)
        {
        for ( int j = 0 ; j < maxlen ; j++)
        {
            cnt[i][j+1] += cnt[i][j]/26;
            cnt[i][j]%=26;
        }
        while (cnt[i][maxlen]>0)
        {
            cnt[i][maxlen+1] += cnt[i][maxlen]/26;
            cnt[i][maxlen]%=26;
            maxlen++;
        }
        }

        for ( int i = 0 ; i < 26 ; i++)
        for ( int j = i+1 ; j < 26 ; j++)
            if (small(cnt[id[i]],cnt[id[j]]))
            swap(id[i],id[j]);
//  for (int i = 0 ; i < 26 ; i++) printf("id[%d]:%c%c",i,char(id[i]+'a'),i==25?'\n':'\n');

    int notBEG = -1;
        if (Beg[id[25]])
        {
        for ( int i = 24 ;  i >= 0 ; i--)
        {
            if (!Beg[id[i]])
            {
            notBEG = i;
            break;
            }
        }
        }
        //cout<<"notBEG:"<<notBEG<<endl;
        if (notBEG!=-1)
        {
        int tmp = id[notBEG];
        for ( int i = notBEG +1 ; i < 26 ; i++) id[i-1] = id[i];
        id[25] = tmp;
        }
        //for ( int i = 0 ; i < 26 ; i++) printf("id[%d]:%c\n",i,char(id[i]+'a'));

        for ( int i = 0 ; i < 26 ; i++) power[id[i]] = 25-i;
        LL ans = 0;
        for ( int i = 1 ; i <= n ; i++)
        {
        int len = st[i].length();
        for ( int j = 0 ; j < len ; j++)
        {
            int pos = len-j-1;
            int v = st[i][j]-'a';
            LL tmp = (base26[pos]*power[v])%mod;
        //    cout<<"tmp:"<<tmp<<endl;
            ans = (ans + tmp)%mod;
        }
        }
        printf("Case #%d: %lld\n",++cas,ans);
            
    }


  #ifndef ONLINE_JUDGE  
  fclose(stdin);
  #endif
    return 0;
}