题意:
给x、y、k,在[x,y] 范围内最长上升子序列长度是k的数有几个
思路:
模仿 LIS nlogn的想法,这里就只有10个数,进行状压
然后直接搜就好了不用二分
然后按位dp下去就ok了!
代码:
#include"cstdlib" #include"cstdio" #include"cstring" #include"cmath" #include"queue" #include"algorithm" #include"iostream" using namespace std; //2014年9月26日09:46:04 __int64 dp[22][1024][11]; int num[22]; struct node { int n,l; }; node js(int n,int x,int tep) { node ans; ans.l=tep; int i; for(i=x; i<10; i++) if(n&(1<<i)) break; if(i==10) //没找到 长度加一 填上那个数 { ans.l=tep+1; n|=(1<<x); } else //找到 更新那个数 { n^=(1<<i); n|=(1<<x); } ans.n=n; return ans; } __int64 dfs(int site,int n,int l,int k,int zero,int f) { if(site==0) { if(zero) return 0; return l==k; } if(!f&&!zero&&~dp[site][n][k]) return dp[site][n][k]; int len=f?num[site]:9; __int64 ans=0; for(int i=0; i<=len; i++) { node tep; if(zero) { if(i==0) ans+=dfs(site-1,n,l,k,zero&&i==0,f&&i==len); else { tep=js(n,i,l); ans+=dfs(site-1,tep.n,tep.l,k,zero&&i==0,f&&i==len); } } else { tep=js(n,i,l); ans+=dfs(site-1,tep.n,tep.l,k,zero&&i==0,f&&i==len); } } if(!f&&!zero) dp[site][n][k]=ans; return ans; } __int64 solve(__int64 x,int k) { int cnt=0; while(x) { num[++cnt]=x%10; x/=10; } return dfs(cnt,0,0,k,1,1); } int main() { int t,cas=1; cin>>t; memset(dp,-1,sizeof(dp)); while(t--) { __int64 x,y; int k; scanf("%I64d%I64d%d",&x,&y,&k); printf("Case #%d: %I64d\n",cas++,solve(y,k)-solve(x-1,k)); } return 0; } //2014年9月26日10:24:07
[数位dp+状态压缩] hdu 4352 XHXJ's LIS
时间: 2024-10-10 16:08:33