N - F(x) HDU - 4734

N - F(x)

HDU - 4734

http://acm.hdu.edu.cn/showproblem.php?pid=4734

题目描述:

0~B里面,F(b)<=F(A)的有多少个。

F(x)=A n * 2 n-1 + A n-1 * 2 n-2 + ... + A 2 * 2 + A 1 * 1. 每位的数*对应2的n次方的和。

分析:

数位dp。dp[pos] [r] 表示在第pos位数,r为该最大数F(A)- 满足的和。

先求最大的F(A),每推到一位,用F(A)-这一位数对应题意的积,得到的就是r。

如果r<0就说明F(b)>F(A)了,直接结束。

memset(dp,-1,sizeof dp)要放在括号前面,不然会T。

代码:

#include<vector> 
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn=1e4;
int F;//上界 
int dp[15][maxn];
int a[20];
int pow2[20];
int dfs(int pos,int r,bool limit)
{
    if(pos==-1) return r>=0;
    if(r<0) return 0;
    if(!limit&&dp[pos][r]!=-1) return dp[pos][r];
    int up=limit?a[pos]:9;
    int ans=0;
    for(int i=0;i<=up;i++)
    {
        if(r<i*pow2[pos]) break;
        ans+=dfs(pos-1,r-i*pow2[pos],limit&&i==a[pos]);
    }
    if(!limit) dp[pos][r]=ans;
    return ans;
}
int solve(int x)
{
    int pos=0;
    while(x)
    {
        a[pos++]=x%10;
        x/=10;
    }
    return dfs(pos-1,F,1);
}
int main()
{
    pow2[0]=1;
    for(int i=1;i<=15;i++)
    {
        pow2[i]=pow2[i-1]*2;
    }
    int T;scanf("%d",&T);
    memset(dp,-1,sizeof dp);
    for(int i=1;i<=T;i++)
    {
        int A,B;
        scanf("%d%d",&A,&B);
        
        F=0;
        int k=0;
        while(A)
        {
            F+=(A%10)*pow2[k];
            A/=10,k++;
        }
        printf("Case #%d: %d\n",i,solve(B));
    }
    return 0;
}
 

猜你喜欢

转载自www.cnblogs.com/studyshare777/p/12484069.html