题目
解说
大致题意就是给你 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 }
幸甚至哉,歌以咏志。