2017多校(第一场)P2(高精度思想)

开始做这个题的时候想着用高精度保存每个字母对和的贡献,开个26位高精度就好了

然后当时就特别困,高精度也是很久以前写的了,就很丢脸的没怼出来

现在补一下题

思路其实还是高精度,但是没有必要拿那种真正的高精度去怼他直接看代码就能理解了

其实这题还是有点练编程能力的

#include <cmath>
#include <algorithm>
#include <cstring>
#include <string>
#include <iostream>
#define Mod 1000000007
#define maxn 100100
#define ll long long

using namespace std;

string s[101000];
ll qz[30][101000];
ll prezero[30];
ll Pow[101000];

void eazy(ll i)//高精度进位
{
    ll li=qz[i][0];
    for (ll k=1;k<=li;k++)
    {qz[i][k+1]+=(qz[i][k]/26);qz[i][k]=qz[i][k]%26;}

    for (ll k=li+1;k<maxn;k++)
    {
        if (qz[i][k]!=0)
        {qz[i][k+1]+=(qz[i][k]/26);qz[i][k]=qz[i][k]%26;}
        else
        {qz[i][0]=k-1;break;}
    }
    return;
}

bool check(ll i,ll j)//高精度比较大小,如果i比j小返回1,否则返回0
{
    if (qz[i][0]>qz[j][0]) return 0;
    else if (qz[i][0]<qz[j][0]) return 1;

    ll len=qz[i][0];
    for (ll k=len;k>0;k--)
        if (qz[i][k]>qz[j][k]) return 0;
        else if (qz[i][k]<qz[j][k]) return 1;

    return 0;
}

int main()
{
    ll n,Case(0);
    Pow[0]=1;
    for (ll k=1;k<=100010;k++)
        Pow[k]=(Pow[k-1]*26)%Mod;//打表打表

    while(~scanf("%lld",&n))
    {
        memset(qz,0,sizeof(qz));
        memset(prezero,0,sizeof(prezero));
        for (ll k=1;k<=n;k++)
        {
            cin>>s[k];
            ll len=s[k].length();
            prezero[s[k][0]-'a']=1;
            for (ll i=0;i<len;i++)//从最高位到最低位遍历
            {
                qz[s[k][i]-'a'][len-i]+=1;//1为最低位len为最高位
                qz[s[k][i]-'a'][0]=max(qz[s[k][i]-'a'][0],len-i);//qz[][1]为最低位qz[][0]为最高位要遍历到纳
            }
        }

        for (ll k=0;k<26;k++)
        {
            qz[k][maxn+1]=k;//因为排序会改变顺序嘛,那就在maxn+1上去保存一下
            eazy(k);
        }

        for (ll i=0;i<26;i++)
            for (ll j=i+1;j<26;j++)
        {
            if (check(i,j))//如果i比j小
            {
                ll lenm=max(qz[i][0],qz[j][0]);
                for (ll k=0;k<=lenm;k++)
                    swap(qz[i][k],qz[j][k]);
                swap(qz[i][maxn+1],qz[j][maxn+1]);
            }
        }//已经从大到小排好序了
         //接下来就是赋值然后算答案了
        ll bo(0);
        for (ll k=25;k>=0;k--)//这个就是把能被赋值为0的权值最小的赋为0其他的按权值大小从25到1进行赋值
        {
            if (!bo)
                if (!prezero[qz[k][maxn+1]]) {qz[k][maxn+2]=0;bo=1;}
                else qz[k][maxn+2]=25-k+1;
            else qz[k][maxn+2]=25-k;//把赋的值保存在maxn+2上
        }

        ll ans(0);

        for (ll k=0;k<26;k++)
            for (ll i=1;i<=qz[k][0];i++)
        {
            ans=(ans+(((qz[k][maxn+2]*qz[k][i])%Mod)*Pow[i-1])%Mod)%Mod;
        }

       /* for (int k=0;k<26;k++)
        {
            cout<<qz[k][maxn+1]<<" "<<qz[k][maxn+2]<<" "<<":";
            for (int i=1;i<=qz[k][0];i++)
                cout<<qz[k][i]<<" ";
            cout<<endl;
        }*/
        Case++;
        printf("Case #%lld: %lld\n",Case,ans);
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值