hdu 4734 数位dp

题意: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).(懒得翻译了哈哈哈)

题解:由于这里要比较的是每个数位的带权和,我们定义dp[i][j]为从i开始枚举,和为j的时候有多少满足题目意思的解

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
using namespace std;
int a[20];
int dp[15][5100];
int len;
int getsum(int x)
{
    int tsum=0;
    int f=1;
    while(x)
    {
        tsum+=(x%10)*f;
        f*=2;
        x/=10;
    }
    return tsum;
}
int dfs(int pos,int sta,int key,bool limit)
{
    if(pos==-1) return 1;
    if(!limit && dp[pos][sta]!=-1 ) return dp[pos][sta];
    int up=limit ? a[pos] : 9;
    int sum=0;
   // cout<<pos<<" "<<up<<endl;

    for(int i=0;i<=up;i++)
    {
        int temp=sta+i*pow(2,pos);
       // cout<<temp<<endl;
        if(temp <= key)
        {
            sum+=dfs(pos-1,temp,key,limit & i==a[pos]);
        }
    }
    if(!limit) dp[pos][sta]=sum;
  //  cout<<"pos: "<<pos<<" "<<"sta :"<<sta<<" "<<"sum :"<<sum<<endl;
    return sum;
}
int solve(int tempa,int b)
{
    int akey=getsum(tempa);
  //  cout<<akey<<endl;
    int pos=0;
    while(b)
    {
        a[pos++]=b%10;
        b/=10;
    }
    len=pos-1;
    return dfs(len,0,akey,true);
}

int main()
{
   int t,Case=0;
   cin>>t;
   while(t--)
   {
       memset(dp,-1,sizeof(dp));
       int aa,b;
       cin>>aa>>b;
       printf("Case #%d: %d
",++Case,solve(aa,b));
   }
    return 0;
}

但是,这个会TLE,没错,会TLE.....

仔细看一下,每次我们都要初始话dp数组,代价有点大,但是按我们刚才的思路来的话,必须每次求的时候都初始话一次

换个思路,dp[i][j]表示枚举到i这个位置的时候,还需要j才能满足条件,这个时候dp数组就和输入的数无关了(em..建议多理理这个不会太好理解)

AC代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
using namespace std;
int a[20];
int dp[15][5100];
int len;
int getsum(int x)
{
    int tsum=0;
    int f=1;
    while(x)
    {
        tsum+=(x%10)*f;
        f*=2;
        x/=10;
    }
    return tsum;
}
int dfs(int pos,int sta,bool limit)// 还需要sta
{
    if(pos==-1) return sta>=0;
    if(sta < 0) return 0;
    if(!limit && dp[pos][sta]!=-1 ) return dp[pos][sta];
    int up=limit ? a[pos] : 9;
    int sum=0;
    for(int i=0;i<=up;i++)
    {
        int temp=sta-i*(1<<pos);
       // cout<<temp<<endl;
        sum+=dfs(pos-1,temp,limit & i==a[pos]);
    }
    if(!limit) dp[pos][sta]=sum;
  //  cout<<"pos: "<<pos<<" "<<"sta :"<<sta<<" "<<"sum :"<<sum<<endl;
    return sum;
}
int solve(int tempa,int b)
{
    int akey=getsum(tempa);
    int pos=0;
    while(b)
    {
        a[pos++]=b%10;
        b/=10;
    }
    len=pos-1;
    return dfs(len,akey,true);
}

int main()
{
   int t,Case=0;
   scanf("%d",&t);
   memset(dp,-1,sizeof(dp));
   while(t--)
   {
      //
       int aa,b;
       scanf("%d %d",&aa,&b);
       printf("Case #%d: %d
",++Case,solve(aa,b));
   }
    return 0;
}
原文地址:https://www.cnblogs.com/z1141000271/p/8408616.html