• [HDU4352] XHXJ's LIS


    题目

    原题链接

    解说

    大致题意就是给你 l r k,问你在[l , r]内把所有数当成一个数列,有多少数的LIS长度为 k 。

    我不知道为什么,大约是在家时间太久倦怠了吧,从进入衡中以来的一种怅然若失的感觉今晚格外强烈,整个人没有干劲呢……这道题可以显然地看出来这是个数位DP想用昨天题的格式试着自己写写,但是就是感觉很颓废写不下去。我知道作为班长我不应该这样,但是我真的快崩溃了,而且现在的颓废让我莫名奇妙地想哭……

    原谅我,好吗?给我一晚上的调整时间,就一晚上,一定会没事的……

    我努力找了几篇解释得最清楚的博客拼了一下,算是勉强看懂了……

    这是怎么了啊?!……


    dp[pos][sta][k]
    pos:搜索到第几位
    sta:之前的最长上升子序列的状态。
    k:就是输入的那个k

    此题的难点就在于中间的那一维--sta。
    sta的二进制每一位,都对应了数位上的一个数字。
    举例来说:如果sta按照数字13425来更新。
    首先遇到1,变成 0100000000 (或者0000000010,其实这是完全一样的,只要保证不同状态的sta不一样就行了)
    然后遇到3,很明显,之前没有比3更大的数字,然后变成0101000000

    遇到4,sta变成0101100000

    在这里打断一下,不能看出,sta中1的个数,就是LIS的长度。

    然后遇到2,这时大于等于2的有一个3.于是把3的二进制1交给2,sta变成0110100000
    为什么这么做?????
    首先我们知道,这样做绝不会改变1的个数,如果之前出现过2,那么sta就不会变化,否则就把之后最近的那个1挪到当前位置。
    然后再看这4个数字:1342
    如果之后出现的数字有比这四个数字都大的,那么之前究竟是1243还是1342都对后方的更新没有影响了。
    就如同例子中的5,它只需知道,在之前出现的数字中最大的没有自己大就行了,因为只要这样,就可把5位置的0变成1。
    注意:如果有多种状态,( 1243 ,1342 ),只要对后续影响相同,就可以看做同一种状态。

    如果之后出现的数字没有比这四个数都大的,那么还是不会改变1的个数。
    但是,出现数字2的时候,第二个1向前挪了一位,这实际上是把LIS为2的序列由13变成了12,这里对后续的影响是不同的,可以手推323来解答你的困惑。

    于是到此我们就知道了sta的真正含义。
    如果sta的第a位上为1,并且之前(包括自己)有b个1,那么长度为b的上升序列的末尾的最小值就是a

    这里还要判断前面是不是有前导0,不然01会被当成LIS是2,但是其实是1.

    引自https://www.cnblogs.com/ZGQblogs/p/10679934.html

    代码

    代码引自https://www.cnblogs.com/kuangbin/archive/2013/05/01/3052657.html

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #include<algorithm>
     5 #include<cmath>
     6 using namespace std;
     7 long long dp[25][1<<10][11];
     8 /*
     9  * dp[i][j][k]:iΪµ±Ç°½øÐе½µÄÊý룬j״̬ѹËõ£¬Îª10¸öÊý×Ö³öÏÖ¹ýµÄ£¬ÆäÖÐ1µÄ¸öÊý¾ÍÊÇ×ÉÏÉý×ÓÐòÁУ¬kÒªÇóµÄÉÏÉý×ÓÐòÁеij¤¶È
    10  */
    11 int K;
    12 int getnews(int x,int s){//¸üÐÂеÄ״̬
    13     for(int i=x;i<10;i++)
    14         if(s&(1<<i))return (s^(1<<i))|(1<<x);
    15     return s|(1<<x);
    16 }
    17 int getnum(int s){//µÃµ½×´Ì¬sÖÐ1µÄ¸öÊý
    18     int ret=0;
    19     while(s){
    20         if(s&1)ret++;
    21         s>>=1;
    22     }
    23     return ret;
    24 }
    25 int bit[25];
    26 long long dfs(int pos,int s,bool e,bool z){
    27 //eÊÇÊDz»ÊÇÉϽç±ê¼Ç£¬zÊÇÊDz»ÊÇÇ°ÃæµÄΪ0±ê¼Ç
    28     if(pos==-1)return getnum(s)==K;
    29     if(!e &&dp[pos][s][K]!=-1)return dp[pos][s][K];
    30     long long ans=0;
    31     int end=e?bit[pos]:9;
    32     for(int i=0;i<=end;i++)
    33         ans+=dfs(pos-1,(z&&i==0)?0:getnews(i,s),e&&i==end,z&&(i==0));
    34     if(!e)dp[pos][s][K]=ans;
    35     return ans;
    36 }
    37 long long calc(long long n){
    38     int len=0;
    39     while(n){
    40         bit[len++]=n%10;
    41         n/=10;
    42     }
    43     return dfs(len-1,0,1,1);
    44 }
    45 int main(){
    46     int T;
    47     long long l,r;
    48     memset(dp,-1,sizeof(dp));
    49     scanf("%d",&T);
    50     int Case=0;
    51     while(T--){
    52         Case++;
    53         scanf("%I64d%I64d%d",&l,&r,&K);
    54         printf("Case #%d: ",Case);
    55         printf("%I64d
    ",calc(r)-calc(l-1));
    56     }
    57     return 0;
    58 }
    View Code

    幸甚至哉,歌以咏志。

  • 相关阅读:
    元类,单例模式
    面向对象高阶
    类的三大特性---封装以及Property特性
    c# 中的string(神奇的string)
    c#中的equal和getHashCode
    linq中的Distinct的使用(附带IComparable和IComparer的复习和使用)
    flex布局完整示例
    flex布局中flex-basis的理解
    CSS两端对齐的效果;
    理解c#中扩展性代码
  • 原文地址:https://www.cnblogs.com/DarthVictor/p/12748353.html
Copyright © 2020-2023  润新知