poj3252 Round Numbers[数位DP]
拆成2进制位做dp记搜就行了,带一下前导0,将0和1的个数带到状态里面,每种0和1的个数讨论一下,累加即可。
WA记录:line29。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 #define dbg(x) cerr<<#x<<" = "<<x<<endl 7 8 using namespace std; 9 typedef long long ll; 10 template<typename T>inline char MIN(T&A,T B){return A>B?A=B,1:0;} 11 template<typename T>inline char MAX(T&A,T B){return A<B?A=B,1:0;} 12 template<typename T>inline T _min(T A,T B){return A<B?A:B;} 13 template<typename T>inline T _max(T A,T B){return A>B?A:B;} 14 template<typename T>inline T read(T&x){ 15 x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1; 16 while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x; 17 } 18 int f[33][33][33][2],b[33]; 19 int l,r; 20 int dp(int len,int s0,int s1,bool lead,bool limit){//ddddbg(len,s0,s1,lead);dbg(limit); 21 if(s0<0||s1<0||s0+s1>len||(!lead&&(s0+s1)^len))return 0; 22 if(!len&&!s0&&!s1)return 1; 23 if(!limit&&~f[len][s0][s1][lead])return f[len][s0][s1][lead]; 24 int cnt=0,num=limit?b[len]:1; 25 if(lead)cnt+=dp(len-1,s0,s1,1,limit&&!num);//填0 26 else cnt+=dp(len-1,s0-1,s1,0,limit&&!num); 27 if(num)cnt+=dp(len-1,s0,s1-1,0,limit);//填1 28 return limit?cnt:f[len][s0][s1][lead]=cnt; 29 }//没有乖乖套模板卡上界判断写错了 30 inline int solve(int x){ 31 int k=0,cnt=0;while(x)b[++k]=x&1,x>>=1;
32 for(register int i=1;i<k;++i)for(register int j=1;j<=_min(i,k-i);++j)cnt+=dp(k,i,j,1,1); 33 return cnt; 34 } 35 36 int main(){//freopen("tmp.txt","r",stdin);//freopen("test.out","w",stdout); 37 memset(f,-1,sizeof f);read(l),read(r); 38 return printf("%d\n",solve(r)-solve(l-1)),0; 39 }