杭电多校 1002 Balala Power! 题解报告

来源:互联网 发布:淘宝客服安抚顾客语 编辑:程序博客网 时间:2024/05/22 16:04

当时看到题目之后是想到巴你奶奶个锤子哦巴
这里写图片描述

题目意思不太好理解
大致说一下
小写字母a-z 中的任何一个字母可以用0-25中的任何一个数字表示
但是每个数字只能对应一个字母
解释一下样例
输入一个数 表示下面会输入几个字符串
然后输入字符串 比如aa bb
a b可以用0-25中的任何一个数字表示 但是 是一个26进制的数
但是要让这个数最大
——26进制转换为10进制的方法——
—1.先看这个26进制的数有多少位 比如123 有三位
—2.然后1*26^2 + 2*26^1 + 3*26^0 = 1*26*26+2*26+3 = 731;
然后a取25 b只能取26
这样aa就是 25*26+25 = 675;
bb就是 24*26+24 = 648;
最后648+675 = 1323;
不知道有没有解释清楚 这题还是大三的学长和我讲解的题意
要注意的就是 0-25任意一个数表示一个字母的时候 是一个26进制的数字 要转换为10进制的数字
所以要做出相应的转换
还有一个前导0的问题 题目要求说 不能有第一个是0的排序 注意
这是思路:
官方题解总是这么简洁 :)

上代码

#include <cstdio>#include <cmath>#include <vector>#include <iostream>#include <set>#include <queue>#include <cstring>#include <algorithm>using namespace std;#define mst(a,b) memset((a),(b),sizeof(a))  // define the reset method #define rush() int T;scanf("%d",&T);while(T--) // define the case statistics methodtypedef long long ll;const int maxn = 100005;const ll mod = 1e9+7;const int INF = 0x3f3f3f;const double eps = 1e-9;int n;char s[maxn];int num[26][maxn];int vis[26];int val[maxn];ll po[maxn];int Max;struct node //{    char xx[maxn]; // deposit the string a-z    int id;}e[26];bool cmp(const node &a,const node &b)  //对贡献从大到小排序{    for(int i=Max-1; i>=0; i--) // Max the lenght of the string     {        if(a.xx[i]>b.xx[i])            return 1;        if(a.xx[i]<b.xx[i])            return 0;    }    return 1;}void init()                 //预处理26^n%mod{    po[0]=1;    for(int i=1; i<maxn; i++)    {        po[i]=(po[i-1]*26)%mod;    }}int main(){       //freopen("input.txt","r",stdin);    //freopen("output.txt","w",stdout);    int n;    int cas=1;    init();    while(~scanf("%d",&n))    {        mst(num,0);        mst(vis,0);        mst(val,0);        for(int i=0; i<n; i++)        {            scanf("%s",s);            int len=strlen(s);            if(len>1)                     //标记这个字母权值不能为零            {                vis[s[0]-'a']=1;  // one point get             }            for(int j=len-1; j>=0; j--)   //统计每个字母在第几位上有几个            {                int o=len-1-j;                num[s[j]-'a'][o]++;            }            Max=max(Max,len);             //减少循环,节约时间        }        for(int i=0; i<26; i++)        {            for(int j=0; j<maxn; j++)            {                if(num[i][j]>=26&&j!=Max-1) //number big than 26,we need to exceed;                {                    num[i][j+1]+=num[i][j]/26; // ?                    num[i][j]%=26; // exceed                 }            }        }        for(int i=0; i<26; i++)        {            for(int j=0; j<Max; j++)            {                e[i].xx[j]=num[i][j]+'a';  //转化为字符形式,节约内存,如果是int可能会爆内存            }            e[i].id=i;        }        sort(e,e+26,cmp);        int pos=-1;        for(int i=25;i>=0;i--)           //从权值小的开始找权值可以为0的字母        {            if(vis[e[i].id]==0)            {                pos=e[i].id; // sign the e[i].id == 0                 break;            }        }        int flag=0;        for(int i=0;i<26;i++)             //给每个字母附上权值        {            if(e[i].id==pos)            {                val[e[i].id]=0;                flag=1;                continue;            }            if(flag==0)  //We have sorted the array.              val[e[i].id]=25-i;            else               val[e[i].id]=25-i+1;        }        ll ans=0;        for(int i=0;i<26;i++)        {            for(int j=0;j<Max;j++)            {                if(num[i][j])                        {                    ll temp=(ll)num[i][j]*val[i]*po[j]%mod;                    ans=(ans+temp)%mod;                }            }        }        printf("Case #%d: %I64d\n",cas++,ans);    }    return 0;}

然后晚一点 我会再回来讲解一下这个代码
先说这么多

代码更新了一下
代码是从这个博客转过来的http://blog.csdn.net/my_sunshine26/article/details/76098497

这一题的思路是要按照字母对26进制数的贡献值进行排序 然后按照排序依次从25开始赋值
统计出每个字母在哪一位出现了几次,然后比较每个字母取能对结果产生的贡献大小。
每个字母从最后一位开始,如果个数大于等于26,则向前进位,以此类推,最终只要从最高位的个数开始比较即可。注意要考虑前导 0
解释一下:为什么如果个数大于等于26,则向前进位
因为26进制数 如果有字幕的个数大于26的话乘不了26^26 所以这里要进位处理。

原创粉丝点击