您的位置:首页 > 其它

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

2017-07-26 14:03 274 查看




题目意思不太好理解

大致说一下

小写字母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 method

typedef long long ll;
const int maxn = 100
4000
005;
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 所以这里要进位处理。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: