XHXJ's LIS---数位DP

来源:互联网 发布:数据恢复后照片无预览 编辑:程序博客网 时间:2024/06/05 19:13

练习了几道数位DP 的题目,数位DP的大框架已经基本上熟悉了。

由于求LIS的长度不超过十位,所以可以用NlogN的求LIS 的方法去更新二进制位的保存的LIS;

具体做法是这样的(看清楚接下来的表述前提是你已经熟悉了数位DP 的dfs做法框架),用一个整数状态表示前面已经得到了的LIS具体出现的数字,比如求出的LIS长度是2,具体Sequence 是12,然后这个整数状态就是3,然后寻找当前最近的比当前位的数字大的Sequence里面的数字,找到之后,这个二进制位置0,当前位置1,至于为什么,就是求LIS  O(NlogN)做法的原理。

#include<iostream>#include<cstdio>#include<cstring>using namespace std;typedef long long LL;const int MAXN = 25;LL dp[MAXN][1<<11][11];LL a,b;int T,k;int num[MAXN],len,cnt[1<<11];//Cnt  数组记录每个数字的二进制表示里面有多少个1void init(){void op(int);memset(dp,-1,sizeof(dp));memset(cnt,0,sizeof(cnt));cnt[0]=1;for(int i=1;i<1025;i++){for(int j=0;j<11;j++){if(i&(1<<j))cnt[i]++;}//printf("cnt[%d](",i);op(i);printf(")->%d\n",cnt[i]);}}void op(int num){if(num==0)return;op(num/2);printf("%d",num%2);}int findAndCancel_next_bitOne(int st,int pos){for(int i=pos;i<11;i++){if(st&(1<<i)){return st^(1<<i);}}return st;}LL dfs(int pos,int st,bool limit){if(pos==0){//printf("st=%d LIS->%d k->%d\n",st,cnt[st],k );return cnt[st]==k;}if(!limit&&dp[pos][st][k]!=-1)return dp[pos][st][k];int end = limit ? num[pos] :9;LL res = 0;int ns;for(int i=0;i<=end;i++){if(st|i){ns = findAndCancel_next_bitOne(st,i);ns |= (1<<(i));res +=dfs(pos-1,ns,limit&&(i==num[pos]));}else{if(i==0){res += dfs(pos-1,st,limit&&(i==limit));}else{res += dfs(pos-1,st|(1<<i),limit&&(i==limit));}}}//if(zero&&pos==1)//printf("-----------%lld\n", res);//printf("pos=%d res=%lld\n",pos,res);if(!limit)dp[pos][st][k]=res;return res;}LL solve(LL n){if(n==0)return k==1;len =1;while(n){num[len++]=n%10;n/=10;}len--;return dfs(len,0,true);}int main(){//freopen("data.in","r",stdin);//freopen("me.out","w",stdout);init();cin>>T;LL r1,r2;for(int i=1;i<=T;i++){cin>>a>>b>>k;r2=solve(b);r1=solve(a-1);cout<<"Case #"<<i<<": ";cout<<r2-r1<<endl;}return 0;}


原创粉丝点击