代码+题解:
1 //题意: 2 //输出在区间[li,ri]中有多少个数是满足这个要求的:这个数的最长递增序列长度等于k 3 //注意是最长序列,可不是子串。子序列是不用紧挨着的 4 // 5 //题解: 6 //很明显前面最长递增序列的长度会影响到后面判断,而且还要注意我们要采用哪种求最长递增序列的方式(一共有两种, 7 //一种复杂度为nlog(n),另一种是n^2),这里我才采用的是nlog(n)的。 8 // 9 //算法思想: 10 //定义d[k]: 11 //长度为k的上升子序列的最末元素,若有多个长度为k的上升子序列,则记录最小的那个最末元素。 12 //定义a[]:a数组放置的是我们要处理的元素 13 //首先len = 1,d[1] = a[1],然后对a[i]:若a[i]>d[len],那么len++,d[len] = a[i]; 14 //否则,我们要从d[1]到d[len-1]中找到一个j,满足d[j-1]<a[i]<d[j],则根据D的定义,我们需要更新长度为j的上升子序列的最末元素(使之为最小的) 15 //即 d[j] = a[i];最终答案就是len 16 // 17 //代码: 18 //d[1] = a[1]; 19 //len=1; 20 //for(i=2; i<=p; ++i) 21 //{ 22 // if(a[i]>d[len]) 23 // d[++len]=a[i]; 24 // else 25 // { 26 // int pos=binary_search(i); // 如果用STL: pos=lower_bound(d,d+len,a[i])-d; 27 // d[pos] = a[i]; 28 // } 29 // printf("%d ",len); 30 //} 31 // 32 //结果: 33 //这个d数组里面放置得结果可能不是正确最长递增序列对应的一个序列,它的长度是可以保证是正确的,但是序列本身不一定 34 // 35 //回归原题: 36 //本体就采用这一种方法来获取最长递增序列,每一个位置都对应一个最长递增序列(虽然这个序列本身不一定对,但是它可以 37 //当作一个状态) 38 //比如一个递增序列为0 1 3 4那么就把它压缩成二进制的每一位,即2^0+2^1+2^3+2^4,这个结果就是我们的状态,这个样子 39 //我们就把0、1、2、3、4、5、6、7、8、9这些状态压缩成了一个值。 40 //然后就写出来了。。。。 41 42 #include<stdio.h> 43 #include<string.h> 44 #include<algorithm> 45 #include<iostream> 46 using namespace std; 47 const int maxn=20; 48 const int N=1<<10; 49 typedef long long ll; 50 ll v[maxn],dp[maxn][N][20],w[15],k; 51 ll update(ll x,ll y) //更新我们压缩的状态 52 { 53 for(ll i=x; i<10; ++i) 54 { 55 if(y&(1<<i)) return ((y^(1<<i))|(1<<x)); 56 } 57 return y|(1<<x); 58 } 59 ll get_num(ll x) 60 { 61 ll ans=0; 62 while(x) 63 { 64 if(x&1) ans++; 65 x>>=1; 66 } 67 return ans; 68 } 69 ll dfs(ll pos,ll sta,bool limit,bool lead) 70 { 71 if(get_num(sta)>k) return 0; 72 if(pos==-1) 73 { 74 if(get_num(sta)==k) 75 return 1; 76 else return 0; 77 } 78 if(!limit && dp[pos][sta][k]!=-1) return dp[pos][sta][k]; 79 ll up=limit?v[pos]:9; 80 ll tmp=0; 81 for(ll i=0; i<=up; ++i) 82 { 83 //这一行可以代替下面的 84 //tmp+=dfs(pos-1,(lead&&i==0)?0:update(i,sta),limit && i==v[pos],lead&&(i==0)); 85 //像下面这样写也对 86 if(lead && i==0) 87 { 88 tmp+=dfs(pos-1,0,limit && i==v[pos],1); 89 90 } 91 else 92 { 93 94 tmp+=dfs(pos-1,update(i,sta),limit && i==v[pos],0); 95 96 } 97 } 98 if(!limit) dp[pos][sta][k]=tmp; 99 //只有上界为9的时候才会往dp数组里面存,因为这样能节省更多的时间 100 return tmp; 101 } 102 ll solve(ll ans) 103 { 104 ll pos=0; 105 while(ans) 106 { 107 v[pos++]=ans%10; 108 ans/=10; 109 } 110 return dfs(pos-1,0,true,1); 111 } 112 int main() 113 { 114 ll t,l,r,p=0; 115 memset(w,0,sizeof(w)); 116 scanf("%I64d",&t); 117 memset(dp,-1,sizeof(dp)); 118 while(t--) 119 { 120 scanf("%I64d%I64d%I64d",&l,&r,&k); 121 printf("Case #%I64d: %I64d ",++p,solve(r)-solve(l-1)); 122 } 123 return 0; 124 }