HDU 4734 - F(x) (数位DP)

题目链接 https://cn.vjudge.net/problem/HDU-4734

【题目描述】
For a decimal number x with n digits (AnAn1An2...A2A1) we define its weight as F(x)=An×2n1+An1×2n2+...+A2×2+A1. Now you are given two numbers A and B, please calculate how many numbers are there between 0 and B, inclusive, whose weight is no more than F(A).

The first line has a number T (T <= 10000) , indicating the number of test cases.
For each test case, there are two numbers A and B (0 <= A,B < 109)

For every case,you should output “Case #t: ” at first, without quotes. The t is the case number starting from 1. Then output the answer.

【思路】
数位DP,设dp[pos][sum] 表示当前处于pos位时,还有sum的权值可以减掉对应的数字个数,根据dp[pos1][sumi×2pos]来计算,边界是当pos==1时,如果 sum>=0 则有一个合法数字,否则没有,当sum<0 时肯定无解,及时停止搜素

#include<bits/stdc++.h>
using namespace std;

int all;
int a[20];
int dp[20][6000];

int F(int x){
    int ans=0;
    int pw=0;
    while(x){
        ans+=(x%10)*(1<<pw);
        x/=10;
        ++pw;
    }
    return ans; 
}

int dfs(int pos,int sum,bool limit){
    if(-1==pos) return sum>=0 ? 1 : 0;
    if(sum<0) return 0;
    if(!limit && dp[pos][sum]!=-1) return dp[pos][sum];

    int up=limit? a[pos] : 9;
    int ans=0;
    for(int i=0;i<=up;++i){
        ans+=dfs(pos-1,sum-i*(1<<pos),limit && i==up);
    }
    if(!limit) dp[pos][sum]=ans;
    return ans;
}

int solve(int x){
    int pos=0;
    while(x){
        a[pos++]=x%10;
        x/=10;
    }
    return dfs(pos-1,all,true);
}

int main(){
    int T;
    scanf("%d",&T);
    memset(dp,-1,sizeof(dp));
    for(int kase=1;kase<=T;++kase){
        int A,B;
        scanf("%d%d",&A,&B);
        all=F(A);
        printf("Case #%d: %d\n",kase,solve(B));
    }
    return 0;
}
posted @ 2018-08-27 15:09  不想吃WA的咸鱼  阅读(88)  评论(0编辑  收藏  举报