CodeForces - 120I Luck is in Numbers

7 篇文章 0 订阅

Problem

  • 给定一个位数为2n的数字,定义该数字的幸运度为将后n位放至前n位在七段码下重叠的段的个数。要求找一个最小的比给定数字大且幸运度更大的数字且位数为2n。

Solution

  • 贪心。只改变前i位的情况下能找到答案就不要修改i+1~2n位。
  • 设需要修改的最高位为pos,分两种情况处理:pos>n和pos<=n。
  • 在寻找最大位的过程中,每移动一位要保证前面位产生的贡献达到最大,此时不需要考虑前i-1位数的大小,因为前i-1位解决不了,第i位需从更大的数开始枚举。
  • 具体步骤:找最大位,从最大位到最小位依次贪心,使当前位在满足题意的基础上尽可能小。细节处理见代码和代码注释。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int dig[200005],cnt,dig0[200005],hl,ans[15][15],wa,ac,ac0,pos,mx[200005];// cnt:位数  hl:位数的一半 
string k;//dig0:初始数   dig:答案  ac:没用  ac0:当前幸运度  wa:初始幸运度  mx:当前每一位产生的最大幸运度
void init()//预处理两个数产生的幸运度
{
    ans[0][0]=6;
    ans[0][1]=ans[1][0]=2;
    ans[0][2]=ans[2][0]=4;
    ans[0][3]=ans[3][0]=4;
    ans[0][4]=ans[4][0]=3;
    ans[0][5]=ans[5][0]=4;
    ans[0][6]=ans[6][0]=5;
    ans[0][7]=ans[7][0]=3;
    ans[0][8]=ans[8][0]=6;
    ans[0][9]=ans[9][0]=5;
    ans[1][1]=2;
    ans[1][2]=ans[2][1]=1;
    ans[1][3]=ans[3][1]=2;
    ans[1][4]=ans[4][1]=2;
    ans[1][5]=ans[5][1]=1;
    ans[1][6]=ans[6][1]=1;
    ans[1][7]=ans[7][1]=2;
    ans[1][8]=ans[8][1]=2;
    ans[1][9]=ans[9][1]=2;
    ans[2][2]=5;
    ans[2][3]=ans[3][2]=4;
    ans[2][4]=ans[4][2]=2;
    ans[2][5]=ans[5][2]=3;
    ans[2][6]=ans[6][2]=4;
    ans[2][7]=ans[7][2]=2;
    ans[2][8]=ans[8][2]=5;
    ans[2][9]=ans[9][2]=4;
    ans[3][3]=5;
    ans[3][4]=ans[4][3]=3;
    ans[3][5]=ans[5][3]=4;
    ans[3][6]=ans[6][3]=4;
    ans[3][7]=ans[7][3]=3;
    ans[3][8]=ans[8][3]=5;
    ans[3][9]=ans[9][3]=5;
    ans[4][4]=4;
    ans[4][5]=ans[5][4]=3;
    ans[4][6]=ans[6][4]=3;
    ans[4][7]=ans[7][4]=2;
    ans[4][8]=ans[8][4]=4;
    ans[4][9]=ans[9][4]=4;
    ans[5][5]=5;
    ans[5][6]=ans[6][5]=5;
    ans[5][7]=ans[7][5]=2;
    ans[5][8]=ans[8][5]=5;
    ans[5][9]=ans[9][5]=5;
    ans[6][6]=6;
    ans[6][7]=ans[7][6]=2;
    ans[6][8]=ans[8][6]=6;
    ans[6][9]=ans[9][6]=5;
    ans[7][7]=3;
    ans[7][8]=ans[8][7]=3;
    ans[7][9]=ans[9][7]=3;
    ans[8][8]=7;
    ans[8][9]=ans[9][8]=6;
    ans[9][9]=6;
}
int main()
{
    freopen("input.txt","r",stdin);
    freopen("output.txt","w",stdout);
    init();
    cin>>k;
    for(int i=0; i<k.size(); i++)
    {
        dig0[k.size()-i]=k[i]-'0';
        dig[k.size()-i]=dig0[k.size()-i];
    }
    cnt=k.size();
    hl=cnt/2;
    for(int i=1; i<=hl; i++)
    {
        wa+=ans[dig0[i]][dig0[i+hl]];
        ac+=ans[dig[i]][dig[i+hl]];
    }
    ac0=ac;
    for(int i=1; i<=hl; i++)// 看最大位是否在前n位 
    {
        bool cmp=0;
        if(i>1)
        {
            ac0-=mx[i-1];
            ac0+=ans[dig[i-1+hl]][dig[i-1+hl]];
            for(int j=9; j>=0; j--)
                if(ans[dig[i-1+hl]][dig[i-1+hl]]==ans[dig[i-1+hl]][j])
                {
                    cmp=j>dig[i-1];
                    break;
                }
            mx[i-1]=ans[dig[i-1+hl]][dig[i-1+hl]];
        }
        for(int j=cmp?dig[i]:dig[i]+1; j<=9; j++)
            mx[i]=max(mx[i],ans[dig[i+hl]][j]);
        ac0=ac0-ans[dig[i+hl]][dig[i]]+mx[i];
        if(ac0>wa)
        {
            pos=i;
            break;
        }
    }
    if(!pos)//最大位在后n位 
    {
        ac0=ac;
        for(int i=cnt; i>hl; i--)//改变前n位使后n位得到最大幸运度 
        {
            ac0=ac0-ans[dig[i]][dig[i-hl]]+ans[dig[i]][dig[i]];
            dig[i-hl]=dig[i];
        }
        for(int i=hl+1; i<=cnt; i++)//寻找最大位 
        {
            bool cmp=0;
            if(i>hl+1)
            {
                ac0=ac0-mx[i-1]+7;
                cmp=dig[i-1]<8;
                mx[i-1]=7;
            }
            for(int j=cmp?dig[i]:dig[i]+1; j<=9; j++)
                mx[i]=max(mx[i],ans[j][j]);
            ac0=ac0-ans[dig[i]][dig[i-hl]]+mx[i];
            if(ac0>wa)
            {
                pos=i;
                break;
            }
        }
        if(!pos)//无解 
        {
            cout<<-1;
            return 0;
        }
        bool cmp=0;
        for(int i=pos; i>hl; i--)//贪心的确定第hl+1~pos位数 
        {
            ac0-=mx[i];
            for(int j=(cmp?0:dig[i]); j<=9; j++)
            {
                if(i==pos&&j==dig[i]) j=dig[i]+1;
                if(ac0+ans[j][j]>wa)
                {
                    ac0+=ans[j][j];
                    if(j>dig[i]) cmp=1;
                    dig[i]=j;
                    dig[i-hl]=j;
                    break;
                }
            }
        }
        for(int i=cnt; i>hl; i--)//确定后n位情况下的最大幸运度 
        {
            ac0=ac0-ans[dig[i]][dig[i-hl]]+ans[dig[i]][dig[i]];
            dig[i-hl]=dig[i];
        }
        for(int i=hl; i>=1; i--)//确定前n位数 
        {
            ac0-=ans[dig[i+hl]][dig[i]];
            for(int j=0; j<=9; j++)
            {
                if(ac0+ans[dig[i+hl]][j]>wa)
                {
                    ac0+=ans[dig[i+hl]][j];
                    dig[i]=j;
                    break;
                }
            }
        }
        for(int i=cnt; i>0; i--)
            cout<<dig[i];
    }
    else//最大位在前n位 
    {
        bool cmp=0;
        for(int i=pos; i>=1; i--)
        {
            ac0-=mx[i];
            for(int j=(cmp?0:dig[i]+1); j<=9; j++)
            {
                if(ac0+ans[dig[i+hl]][j]>wa)
                {
                    if(j>dig[i]) cmp=1;
                    dig[i]=j;
                    ac0+=ans[dig[i+hl]][j];
                    break;
                }
            }
        }
        for(int i=cnt; i>0; i--)
            cout<<dig[i];
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哈希表扁豆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值