您的位置:首页 > 其它

hdu 4734 F(x) (数位DP中dp数组的重用)

2017-11-18 14:26 417 查看
F(x)
Time Limit : 1000/500ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 18   Accepted Submission(s) : 9
[align=left]Problem Description[/align]
For a decimal number x with n digits (AnAn-1An-2 ... A2A1),
we define its weight as F(x) = An * 2n-1 + An-1 * 2n-2 + ... + A2
* 2 + A1 * 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).
 

[align=left]Input[/align]
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 < 10[sup]9[/sup])
 

[align=left]Output[/align]
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.
 

[align=left]Sample Input[/align]

3
0 100
1 10
5 100

 

[align=left]Sample Output[/align]

Case #1: 1
Case #2: 2
Case #3: 13

 

[align=left]Source[/align]
2013 ACM/ICPC Asia Regional Chengdu Online
 

题意:
一个A,问你在[0,B]中有多少数,使得F(x)<=F(A)  A=(AnAn-1An-2 ... A2A1),
 F(x) = An * 2n-1 + An-1 * 2n-2 + ... + A2
* 2 + A1 * 1

解析:
这道题数据倒是挺小的,主要是卡时间0.5s,对于每一次输入都memset一遍DP,一定会超时。
所以这道题就要重用dp数组,只需要在所有数据输入前初始化一次就够了。
那么这就要使dp与每一次输入的F(A)无关,这样就要使dp的第二个状态记录,在pos位时,距离边界还剩多少,其实就是F(A)-state,state为pos位之前所有数字的权值和。
那么我的state,就是记录对于目标还剩多少

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

typedef long long int ll;

int a[13];
ll dp[10][5000];
ll FA;
ll two[10];

ll dfs(int pos,ll state,bool limit,bool lead)
{
ll ans=0;
if(pos==-1)
{
        if(state>=0)
            return 1;
        else
            return 0;
}

    if(state<0) return 0;

if(!limit/*&&!lead*/&&dp[pos][state]!=-1) return dp[pos][state];

int up=limit?a[pos]:9;

    
for(int i=0;i<=up;i++)
{
        if(state-i*two[pos]>=0)
            ans+=dfs(pos-1,state-i*two[pos],limit&&i==up,lead&&i==0);
}

if(!limit/*&&!lead*/) dp[pos][state]=ans;
return ans;

}

ll solve(ll n)
{
ll ans=0;
int pos=0;
while(n)
{
a[pos++]=n%10;
n=n/10;
}
//memset(dp,-1,sizeof(dp));
ans+=dfs(pos-1,FA,true,true);
return ans;
}

int main()
{
int t;
ll A,B;
scanf("%d",&t);
    two[0]=1;
    for(int i=1;i<10;i++)
    {
        two[i]=two[i-1]*2;
    }
    int k=0;
    memset(dp,-1,sizeof(dp));
while(t--)
{
        k++;
scanf("%lld%lld",&A,&B);
        FA=0;
        int j=0;
        while(A)
        {
            int tmp=A%10;
            FA+=tmp*two[j];
            j++;
            A=A/10;
        }
        if(FA>=5000)   //因为当B为999999999时,权值最大为4608,不加也没事,不影响时间
            printf("Case #%d: %lld\n",k,B+1);
        else
            printf("Case #%d: %lld\n",k,solve(B));
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ACM acm专项训练 dp hdu