sgu-258 Almost Lucky Numbers

59 篇文章 1 订阅
9 篇文章 0 订阅
题目大意:

定义幸运数字为有 2N 位的数,并且前 N 位和后N位的数字之和相等。
定义近似幸运数字为有 2N 位的数,改动其中一位后(不能出现前导零,并且必须变动,也就是说幸运数字一定不是近似幸运数字)满足是幸运数字。
然后现在给你 A,B(A,B<=109) ,要你求出 [A,B] 中近似幸运数字的个数。

解题思路:

一道恶心的 dp ,写了我几个小时啊。。。。。。。。。
这种题目显然都是转化成求 ans([1,B])ans([1,A1]) ,所以我们只需要考虑求 [1,K] 的情况就行了。
显然根据位数我们可以分类:
[10,99],[1000,9999],[100000,999999],[1000000,99999999]
然后如果 [1,K] 完全包含了某个区间,就直接统计把答案统计进去就行了。我们假设 K ,将某个区间给分开了,也就是说K在上面的四个区间中的一个中,那么我们就需要单独考虑一下这个区间怎么做。
如果 K 的位数是奇数,那么很简单,直接统计包含了几个区间就行了,因为奇数位是不可能分割以上区间的。
那么如果是偶数位,假设位数为2t,那么现在我们转化为求:
[102t1,K] ,区间中有多少个近似幸运数。
我们发现,现在这个问题的区间中的数的位数都是相同的,然后我们分开考虑前 t 位和后t位。
我们令 F1[i][j][p][q][0,1] 表示前 t 位中,1i位的和为 j ,如果将其中一个数字变小最多可以减小p,将其中一个数字变大最多可以增加 q (等价于最大的数为p,最小的数为 9q PS: 如果是第一位的话那么是不能为0的,对于第一位最大的数应该是 p+1 ,最小的数不变还是为 9q ),第 5 维为0表示 1i 位没有达到 K 的上界,为1表示等于 K 的前1i位,这样的数有多少个。
然后我们令 F2[i][j][p][q][0,1] F3[i][j][p][q][0,1] t+1t+i 中的剩下几维与 F1 中定义相同的数的个数。
然后就是三个的初值:
F1[0][0][0][0][1]=1F2[0][0][0][0][1]=1F3[0][0][0][0][0]=1 剩下的都是 0 ,也就相当于F2考虑的是前 t 为都达到了上界的情况,F3表示前 t <script type="math/tex" id="MathJax-Element-9147">t</script>位没有达到上界的情况。
转移方程和输出答案详见程序吧,感觉很难讲啊。

AC代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>

using namespace std;

long long A,B;
int F[20]={0};

long long counts(int lenth,int num[])
{
    long long returnd=0;
    int F1[20][50][10][10][2]={{{{{0}}}}};
    int F2[20][50][10][10][2]={{{{{0}}}}};
    int F3[20][50][10][10][2]={{{{{0}}}}};
    F1[0][0][0][0][1]=F2[0][0][0][0][1]=F3[0][0][0][0][0]=1;
    for(int i=0;i<(lenth>>1);i++)
    {
        for(int ss=0;ss<=i*9;ss++)
        {
            for(int p=0;p<=9;p++)
                for(int q=0;q<=9;q++)
                {
                    for(int j=(i+1==1);j<=9;j++)
                    {
                        if(j<=num[i+1])
                            F1[i+1][ss+j][max(p,j-(i+1==1))][max(q,9-j)][j==num[i+1]]+=F1[i][ss][p][q][1];
                        F1[i+1][ss+j][max(p,j-(i+1==1))][max(q,9-j)][0]+=F1[i][ss][p][q][0];
                    }
                }
        }
    }
    for(int i=0;i<(lenth>>1);i++)
    {
        for(int ss=0;ss<=i*9;ss++)
        {
            for(int p=0;p<=9;p++)
                for(int q=0;q<=9;q++)
                {
                    for(int j=0;j<=9;j++)
                    {
                        if(j<=num[i+1+(lenth>>1)])
                            F2[i+1][ss+j][max(p,j)][max(q,9-j)][j==num[i+1+(lenth>>1)]]+=F2[i][ss][p][q][1];
                        F2[i+1][ss+j][max(p,j)][max(q,9-j)][0]+=F2[i][ss][p][q][0];
                    }
                }
        }
    }
    for(int i=0;i<(lenth>>1);i++)
    {
        for(int ss=0;ss<=i*9;ss++)
        {
            for(int p=0;p<=9;p++)
                for(int q=0;q<=9;q++)
                {
                    for(int j=0;j<=9;j++)
                    {
                        if(j<=num[i+1+(lenth>>1)])
                            F3[i+1][ss+j][max(p,j)][max(q,9-j)][j==num[i+1+(lenth>>1)]]+=F3[i][ss][p][q][1];
                        F3[i+1][ss+j][max(p,j)][max(q,9-j)][0]+=F3[i][ss][p][q][0];
                    }
                }
        }
    }
    for(int ss=0;ss<=(lenth>>1)*9;ss++)
    {
        for(int p1=0;p1<=9;p1++)
            for(int q1=0;q1<=9;q1++)
                for(int p2=0;p2<=9;p2++)
                    for(int q2=0;q2<=9;q2++)
                    {
                        int Max=max(p1,q2);
                        for(int g=ss+1;g<=ss+Max;g++)
                        {
                            returnd+=F1[(lenth>>1)][g][p1][q1][1]*(F2[(lenth>>1)][ss][p2][q2][0]+F2[(lenth>>1)][ss][p2][q2][1]);
                            returnd+=F1[(lenth>>1)][g][p1][q1][0]*F3[(lenth>>1)][ss][p2][q2][0];
                        }
                        Max=max(q1,p2);
                        for(int g=max(0,ss-Max);g<ss;g++)
                        {
                            returnd+=F1[(lenth>>1)][g][p1][q1][1]*(F2[(lenth>>1)][ss][p2][q2][0]+F2[(lenth>>1)][ss][p2][q2][1]);
                            returnd+=F1[(lenth>>1)][g][p1][q1][0]*F3[(lenth>>1)][ss][p2][q2][0];
                        }
                    }
    }
    return returnd;
}

long long Getans(long long K)
{
    int num[20]={0};
    int lenth=0;
    long long returnd=0;
    for(;K>0;)
    {
        num[++lenth]=K%10;
        K/=10;
    }
    for(int i=2;i<lenth;i+=2)
        returnd+=F[i];
    reverse(num+1,num+lenth+1);
    if(!(lenth&1) && lenth>0)
    returnd+=counts(lenth,num);
    return returnd;
}

int main()
{
    F[2]=81;F[4]=7389;F[6]=676133;F[8]=62563644;
    cin>>A>>B;
    long long ans=Getans(B)-Getans(A-1);
    cout<<ans<<endl;
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值