hdu 4734 F(x)

題意:給你A和B,讓你求0~~B中F(x)< = F(A)  的x的個數,滿足F(x) = An * 2n-1 + An-1 * 2n-2 + ... + A2 * 2 + A1 * 1;

分析:當我做到這題的時候一個很清晰的細節就是,給我們10的9次方範圍,0.5s的時限,最大的F(x)總和也不到7000,T(測試樣例)還很大,容易想到的就是數位DP,至於怎麼數位DP,可以發現,它的第i位和第i+1位有關聯,於是得到狀態轉移方程:dp [ i ] [ j ] [ k + 2 ^ ( i - 1 ) * j ] + = sum { dp[ i - 1 ] [ t ] [ k ] } ; dp [ i ] [ j ] [ k ]表示第i位是J的時候總和爲K的個數;

代碼如下:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;
const int maxn = 7000;
int dp[12][12][maxn];
int sum[12][12][maxn];
void init(){
    memset(dp,0,sizeof(dp));
    memset(sum,0,sizeof(sum));
    dp[0][0][0]=1;
    for(int i=1;i<11;i++){
        for(int j=0;j<=9;j++){
            for(int k=0;k<maxn-500;k++){
                int t1=k+(1<<(i-1))*j;
                for(int t=0;t<=9;t++){
                    dp[i][j][t1]+=dp[i-1][t][k];
                }
                if(k==0) sum[i][j][k]=dp[i][j][k];
                else
                sum[i][j][k]=sum[i][j][k-1]+dp[i][j][k];
            }
        }
    }
}
int w[12];
int dige(int n){
    int ret=0;
    while(n){
        w[++ret]=n%10;
        n/=10;
    }
    return ret;
}
int work(int n,int M){
    int dig=dige(n);
   // printf("%d\n",dig);
    int flag=0;
    int ans=0;
    for(int i=dig;i>=1;i--){
        for(int j=0;j<w[i];j++){
            ans+=sum[i][j][M-flag];
        }
        flag+=w[i]*(1<<(i-1));
        if(flag>M) break;
    }
    return ans;
}
int main(){
    int T;
    init();
    scanf("%d",&T);
    int con=1;
    while(T--){
        int a,b;
        scanf("%d %d",&a,&b);
        int fa=0;
        int wei=0;
        while(a){
            fa+=(a%10)*(1<<wei);
            a/=10;
            wei++;
        }
        printf("Case #%d: %d\n",con++,work(b+1,fa));
    }
}

發佈了29 篇原創文章 · 獲贊 2 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章