[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\n",calc(r)-calc(l-1));
56     }
57     return 0;
58 }
View Code

幸甚至哉,歌以咏志。

posted @ 2020-04-21 22:16  DarthVictor  阅读(383)  评论(2编辑  收藏  举报
莫挨老子!