HDU6034 Balala Power!

Balala Power!

这道题的题意就是给你n个字符串,让你对每个字符赋值(0~25)(注意,每种字符只能赋一个值),然后让你求这些字符的26进制的和的最大值,并且用十进制输出这个最大值。

解释一下样例,
第一个样例,用25对a赋值即可。
第二个样例,用25对a赋值,用24对b赋值(反过来也可以),aa = 25 * 26 + 25 = 675, bb = 24 * 26 + 24 = 648,
aa + bb = 675 + 648 = 1323
第三个样例,用25对a赋值,用24对b赋值,用23对c赋值,a = 25, ba = 24 * 26 + 25 = 649, abc = 25 * 26^2 + 24 * 26 + 23 = 17547, a + ba + abc = 18221
做完这几个样例,相信大家有点感觉了,只要对最高位上的出现次数最多的字符赋最大的值就可以了,如果最高位上的字符一样多,就右找。
还有一点要注意的是这道题的字符串,如果长度大于等于2,第一位不能赋零。就是说比如给你30个a,30个b……30个y 和一个za,按照之前的排序规则,z出现次数最少,就应该赋零,在这条规则下,z只能被赋1,而b~y中的任意一种字母被赋零。

代码如下:

#include
using namespace std;
typedef long long ll;

const int maxn = 100020;
const int mod = 1e9 + 7;
int base[maxn]; //预处理基数数组
int sum[maxn];
int num[26][maxn]; //第一维表示a~z对应的数,a对应1,b对应2……,第二位表示该字符出现的次数
int maxlen = 0;
int vis[26];

char str[maxn];
int rate[26];
bool cmp(int a, int b)//以出现次数更少且所在位更低的字符为优先排序(因为待会要反转字符串,最高位的其实是最低位)
{
    for(int i = maxlen - 1; i >= 0; --i)
    {
        if(num[a][i] != num[b][i])
        {
            return num[a][i] < num[b][i];
        }
    }
    return 0;
}

int main()
{
    base[0] = 1;
    for(int i = 1; i < maxn; ++i)//预处理基数数组
    {
        base[i]= (ll)base[i-1] * 26 % mod ;
    }
    int cas=0, n;
    while(~scanf("%d", &n))
    {
        memset(vis, 0, sizeof(vis));
        memset(sum, 0, sizeof(sum));
        memset(num, 0, sizeof(num));
        maxlen=0;

        for(int i = 0; i < n; ++i)
        {
            scanf("%s", str);
            int len = strlen(str);
            if(len > 1) vis[str[0] - 'a'] = 1; //对于字符串长度大于等于2字符串的第一个字母进行标记,不能被赋零。

            reverse(str, str + len);//反转字符串,接下来的操作时下标可以写的方便些。
            for(int j = 0; j < len; ++ j)//记录每个字符出现次数
            {
                ++ num[str[j] - 'a'][j];
                sum[str[j] - 'a']+= base[j];//同时将每个字符在各个位的基数幂的和求出来,这样待会直接乘对应的(0~25)就行了。
                if(sum[str[j] - 'a'] >= mod)//取模
                {
                    sum[str[j] - 'a']-= mod;
                }
            }
            maxlen = max(maxlen,len);//更新字符串最大长度
        }
        for(int i = 0; i < 26; ++i)//为计算字符串中那个是最高位出现次是最多的做准备,逢26进1,最高位进位就更新maxlen
        {
            for(int j = 0; j < maxlen; ++j)
            {
                num[i][j + 1]+= num[i][j]/26;
                num[i][j]%= 26;
            }
            while(num[i][maxlen])
            {
                num[i][maxlen + 1]+= num[i][maxlen] / 26;
                num[i][maxlen++]%= 26;
            }
            rate[i]=i;
        }
        sort(rate, rate + 26, cmp);//排序
        int pos = -1;
        for(int i = 0; i < 26; ++i)//找出要赋零的字符
        {
            if(!vis[rate[i]])
            {
                pos = rate[i];
                break;
            }
        }
        int dic = 25;
        ll ans = 0;
        for(int i = 25; i >= 0; --i)
        {
            if(rate[i] != pos)
            {
                ans+= (ll)(dic--) * sum[rate[i]] % mod;//直接乘以相应的权值,算出最后的答案
                ans%= mod;
            }
        }
        ans = ans % mod;
        cas++;
        printf("Case #%d: %lld\n", cas, ans);

    }

}

你可能感兴趣的:(字符串,字符串)