HDU 4352:XHXJ's LIS

题目:(原题是英文而且很迷) 求区间内数的LIS长度==k的个数,比如153948的LIS为1 3 4 8,长度为4。据说这种题叫DP中DP,本来是线性,再套一层状压+数位,简直厉害到不行……

线性的部分为O(nlogn)的LIS。比如现在找出的序列为1 3 4 8,两个策略,如果再来一个2就变成1 2 4 8(二分找第一个比它大的数),再来9就变成1 2 4 8 9(更新长度)。代码在下面

 

 1 #include<cstdio>
 2 #include<ctime>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<algorithm>
 6 using namespace std;
 7 int n,f[1010],x,l,r,len;
 8 int main()
 9 {
10     scanf("%d",&n);
11     f[0]=-1;
12     for(int i=1;i<=n;++i){
13         scanf("%d",&x);
14         l=1;r=len;
15         if(x>f[len]){
16             f[++len]=x;
17             continue;
18         }
19         while(l<r){
20             int mid=(l+r)>>1;
21             if(x>f[mid]) l=mid+1;
22             else r=mid;
23         }
24         f[l]=x;
25     }
26     printf("%d",len);
27     return 0;
28 }

 

然后我们就要数位里状压了。我们知道对于0~9的LIS最长是10,那就可以用二进制来表示LIS的状态。还用上面的例子1 3 4 8,表示为0100011010。然后dp的时候发现状态的更新并没有那么方便,不过我们可以预处理LIS的更新情况,建立状态之间的联系,比如1 3 4 8--插入2-->1 2 4 8。之后直接套进数位DP的板子就做完了,并没有看起来那么难。

 

 1 #include<cstdio>
 2 #include<cmath>
 3 #include<ctime>
 4 #include<cstring>
 5 #include<iostream>
 6 #include<algorithm>
 7 #include<queue>
 8 #include<vector>
 9 #define ll long long
10 using namespace std;
11 const int base=1<<10;
12 int k,siz[base],dig[base],ne[base][11];
13 ll f[20][base][11];
14 ll dfs(int w,int sta,bool o,bool pd)
15 {
16     if(!w) return siz[sta]==k;
17     if((!pd)&&(f[w][sta][k]!=-1)) return f[w][sta][k];
18     ll up=pd?dig[w]:9,tmp(0);
19     for(int i=0;i<=up;++i) tmp+=dfs(w-1,(o&(!i))?0:ne[sta][i],o&(!i),pd&(i==up));
20     if(!pd) f[w][sta][k]=tmp;
21     return tmp; 
22 }
23 ll F(ll num)
24 {
25     int wei(0);
26     while(num){
27         dig[++wei]=num%10;
28         num/=10;
29     }
30     return dfs(wei,0,1,1);
31 }
32 int fnd(int i,int num)
33 {
34     for(int j=num;j<10;++j) if(i&(1<<j)) return i^(1<<j)|(1<<num); 
35     return i|(1<<num);
36 }
37 int main()
38 {
39     ll T,l,r;
40     memset(f,-1,sizeof(f));
41     for(int i=0;i<base;++i){
42         for(int j=0;j<10;++j){
43             if(i&(1<<j)) siz[i]++;
44             ne[i][j]=fnd(i,j);
45         }
46     }
47     scanf("%d",&T);
48     for(int i=1;i<=T;++i){
49         scanf("%lld%lld%d",&l,&r,&k);
50         printf("Case #%d: %lld\n",i,F(r)-F(l-1));
51     }
52     return 0;
53 }

 

posted @ 2017-11-04 17:17  五十岚芒果酱  阅读(242)  评论(0编辑  收藏  举报