这个题最不好想到的是状态的保存,也没有几亿的数组让你开,怎么保存前面出现了哪些数字。
题意让你求最长上升子序列的长度为k的数字的数目,可以是不连续的,可以保留一个状态栈,栈顶部依次更新,再保证长度最大的情况下使栈顶元素最小,这样就能保证下次加进来的元素有可能会使长度增加。这个状态就用2进制来表示,1的个数就是最后的长度。
1 #include <iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<stdlib.h> 6 #include<vector> 7 #include<cmath> 8 #include<queue> 9 #include<set> 10 using namespace std; 11 #define N 100000 12 #define LL long long 13 #define INF 0xfffffff 14 const double eps = 1e-8; 15 const double pi = acos(-1.0); 16 const double inf = ~0u>>2; 17 LL dp[22][1<<10][11]; 18 int dd[22],k,d[22]; 19 LL dfs(int i,int e,int tt) 20 { 21 if(i==-1) 22 { 23 int num = 0; 24 for(int g = 0 ;g <= 9 ;g++) 25 if((1<<g)&tt) 26 num++; 27 return num==k; 28 } 29 if(!e&&dp[i][tt][k]!=-1) return dp[i][tt][k]; 30 int mk = e?d[i]:9; 31 LL ans = 0; 32 int j; 33 for(j=0;j <= mk ; j++) 34 { 35 int te = tt; 36 for(int g = j; g <= 9 ; g++) 37 { 38 if((1<<g)&tt) 39 { 40 te-=(1<<g); 41 break; 42 } 43 } 44 if(tt||j!=0) 45 te|=(1<<j); 46 ans+=dfs(i-1,e&&j==mk,te); 47 } 48 return e?ans:dp[i][tt][k] = ans; 49 } 50 LL cal(LL x) 51 { 52 int dd[11]; 53 memset(dd,0,sizeof(dd)); 54 int g = 0; 55 while(x) 56 { 57 d[g++] = x%10; 58 x/=10; 59 } 60 return dfs(g-1,1,0); 61 } 62 int main() 63 { 64 int t; 65 LL l,r; 66 cin>>t; 67 memset(dp,-1,sizeof(dp)); 68 int kk =0 ; 69 while(t--) 70 { 71 cin>>l>>r>>k; 72 printf("Case #%d: ",++kk); 73 cout<<cal(r)-cal(l-1)<<endl; 74 } 75 return 0; 76 }