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

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

【题目描述】
For a decimal number x with n digits ( A n A n 1 A n 2 . . . A 2 A 1 ) we define its weight as F ( x ) = A n × 2 n 1 + A n 1 × 2 n 2 + . . . + A 2 × 2 + A 1 . 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,设 d p [ p o s ] [ s u m ] 表示当前处于pos位时,还有sum的权值可以减掉对应的数字个数,根据 d p [ p o s 1 ] [ s u m i × 2 p o s ] 来计算,边界是当 p o s == 1 时,如果 s u m >= 0 则有一个合法数字,否则没有,当 s u m < 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;
}

猜你喜欢

转载自blog.csdn.net/xiao_k666/article/details/82113183