hdu 4734 F(x)

来源:互联网 发布:点雇网 在线全职美工 编辑:程序博客网 时间:2024/05/01 07:13

题意:给你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));    }}

原创粉丝点击