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\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; }