题意:求区间L到R之间的数A满足A的的数位的最长递增序列的长度为K的数的个数。
链接:点我
该题的关键是记录LIS的状态,学习过nlogn解法的同学都知道,我们每次加入的元素要和前面的比对替换,这里就用了这个方法
比如1 3 6,用二进制表示为001000101,假如新加入的数为2,那么我们枚举比2大的数,观察是否存在,这里找到3,我们把3替换成2,状态变成1,2,6
不懂的童鞋可以看这里的nlogn的介绍:点我
还有就是注意前导0
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 #include<queue> 7 #include<map> 8 using namespace std; 9 #define MOD 1000000007 10 typedef long long ll; 11 const int INF=0x3f3f3f3f; 12 const double eps=1e-5; 13 #define cl(a) memset(a,0,sizeof(a)) 14 #define ts printf("***** "); 15 const int MAXN=1005; 16 int n,m,tt,K; 17 ll dp[20][1<<11][11]; 18 int digit[20]; 19 int k; 20 ll getst(ll s,ll u,ll& xx) // 状态转移 21 { 22 ll i,ss; 23 for(i=u;i<10;i++) 24 { 25 if(s&(1<<i)) break ; //有比u大的,替换掉 26 } 27 if(i<10) 28 { 29 ss=s^(1<<i); 30 ss=ss^(1<<u); 31 } 32 else //没有比u大的,u放入s中 33 { 34 xx++; 35 ss=s^(1<<u); 36 } 37 return ss; 38 } 39 ll dfs(int p,ll s,ll len,int fl,bool e) { //位置,lis状态,lis长度,前导0 40 if (p==-1) return len==k; 41 if (!e &&dp[p][s][k]!=-1) return dp[p][s][k]; 42 ll res = 0; 43 int u=e?digit[p]:9; 44 for (int i=0;i<=u;++i) 45 { 46 ll ns,nlen=len; 47 if(fl==0&&i==0) ns=0; 48 else ns=getst(s,i,nlen); 49 res+=dfs(p-1,ns,nlen,fl||i!=0,e&&i==u); 50 } 51 return e?res:dp[p][s][k]=res; 52 } 53 ll solve(ll n) 54 { 55 int len=0; 56 while(n) 57 { 58 digit[len++]=n%10; 59 n/=10; 60 } 61 return dfs(len-1,0,0,0,1); 62 } 63 int main() 64 { 65 int i,j; 66 #ifndef ONLINE_JUDGE 67 freopen("1.in","r",stdin); 68 #endif 69 scanf("%d",&tt); 70 int ca=0; 71 memset(dp,-1,sizeof(dp)); 72 while(tt--) 73 { 74 ll l,r; 75 scanf("%I64d%I64d%I64d",&l,&r,&k); 76 ll ans=solve(r)-solve(l-1); 77 printf("Case #%d: %I64d ",++ca,ans); 78 } 79 }