考虑LIS的一种求法:维护每一个长度的最小结尾,此时这个序列只与每一个数字有没有出现有关,用2^10状压,状压+数位dp即可
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 int t,k,a[21]; 5 ll l,r,f[21][11][2005]; 6 int count(int k){ 7 int ans=0; 8 while (k){ 9 k&=k-1; 10 ans++; 11 } 12 return ans; 13 } 14 ll dfs(int k,int t,int s,int p1,int p2){ 15 if (!k)return count(s)==t; 16 if ((p1)&&(p2)&&(f[k][t][s]>=0))return f[k][t][s]; 17 int ma=9,la=-1,ss; 18 ll ans=0; 19 if (!p2)ma=a[k]; 20 for(int i=9;i>ma;i--) 21 if (s&(1<<i))la=i; 22 for(int i=ma;i>=0;i--){ 23 if (s&(1<<i))la=i; 24 ss=s; 25 if ((p1)||(i))ss+=(1<<i); 26 if (la>=0)ss-=(1<<la); 27 ans+=dfs(k-1,t,ss,p1|(i>0),p2|(i<ma)); 28 } 29 if ((p1)&&(p2))f[k][t][s]=ans; 30 return ans; 31 } 32 ll calc(ll k,int p){ 33 for(a[0]=0;k;k/=10)a[++a[0]]=k%10; 34 return dfs(a[0],p,0,0,0); 35 } 36 int main(){ 37 scanf("%d",&t); 38 memset(f,-1,sizeof(f)); 39 for(int ii=1;ii<=t;ii++){ 40 scanf("%lld%lld%d",&l,&r,&k); 41 printf("Case #%d: %lld\n",ii,calc(r,k)-calc(l-1,k)); 42 } 43 }