码迷,mamicode.com
首页 > 其他好文 > 详细

sgu-258 Almost Lucky Numbers

时间:2015-06-01 14:45:14      阅读:203      评论:0      收藏:0      [点我收藏+]

标签:

题目大意:

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

解题思路:

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

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;
}

sgu-258 Almost Lucky Numbers

标签:

原文地址:http://blog.csdn.net/qq_21995319/article/details/46309849

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!