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

来源:互联网 发布:nginx https转发http 编辑:程序博客网 时间:2024/06/05 19:01
F(x)
Time Limit : 1000/500ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 18   Accepted Submission(s) : 9
Problem Description
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).
 

Input
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])
 

Output
For every case,you should output "Case #t: " at first, without quotes. The [I]t[/I] is the case number starting from 1. Then output the answer.
 

Sample Input
30 1001 105 100
 

Sample Output
Case #1: 1Case #2: 2Case #3: 13
 

Source
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));    }}


原创粉丝点击