sgu-258 Almost Lucky Numbers

題目大意:

定義幸運數字爲有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 ,最小的數爲9qPS: 如果是第一位的話那麼是不能爲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 位沒有達到上界的情況。
轉移方程和輸出答案詳見程序吧,感覺很難講啊。

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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章