1. 程式人生 > >hdu 4734 數位dp

hdu 4734 數位dp

枚舉 ets hdu eas ring stream urn 哈哈 mem

題意: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\n",++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\n",++Case,solve(aa,b));
   }
    return 0;
}

hdu 4734 數位dp