zoukankan      html  css  js  c++  java
  • 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
    ",i,F(r)-F(l-1));
    51     }
    52     return 0;
    53 }
  • 相关阅读:
    tars go版本源码分析
    goim源码阅读
    vue weixin源码解读
    避免加锁的骚操作
    git一些常用操作
    eclipse 的习惯配置
    ai资源站
    转载 github上的一些安全资源收集
    转载 一个统计代码行数的python脚本
    C语言开发工具
  • 原文地址:https://www.cnblogs.com/12mango/p/7783916.html
Copyright © 2011-2022 走看看