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

本文介绍了一种算法问题,涉及26进制数的转换与最大值求解。通过将小写字母映射到0-25之间的数字,并确保每个数字只对应一个字母,来解决如何使由这些字母组成的字符串表示的最大26进制数值问题。文章提供了详细的思路解析及代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

题目意思不太好理解
大致说一下
小写字母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 = 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.youkuaiyun.com/my_sunshine26/article/details/76098497

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值