题意:给定一个区间[a,b]和一个数字k,求区间内符合LIS为k的数字的个数。
由O(nlogn)的LIS算法中可以得到启发,可以压缩前面的数中某个数字出现与否,然后每加入一个新的数,在这个状态上修改即可。
#include<iostream> #include<cmath> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #define FOR(i,x,y) for(int i=(x);i<=(y);i++) #define DOR(i,x,y) for(int i=(x);i>=(y);i--) typedef long long LL; using namespace std; int num[23]; LL dp[23][13][(1<<10)+3]; int get_ans(int status) { int res=0; FOR(i,0,9)res+=((status&(1<<i))>0); return res; } int get_new_status(int status,int x) { FOR(i,x,9)if(status&(1<<i))return (status^(1<<i)|(1<<x)); return status|(1<<x); } LL dfs(int k,int lth,int status,bool ismax) { if(k==0)return lth==get_ans(status); if(!ismax && dp[k][lth][status]!=-1)return dp[k][lth][status]; int maxer=ismax?num[k]:9; LL res=0; FOR(i,0,maxer) //特判前面全0 res+=dfs(k-1,lth,status==0&&i==0?0:get_new_status(status,i),ismax&&i==maxer); if(!ismax)dp[k][lth][status]=res; return res; } LL solve(LL k,int f) { int p=0; while(k) { num[++p]=k%10; k/=10; } return dfs(p,f,0,1); } int main() { int T; scanf("%d",&T); memset(dp,-1,sizeof(dp)); FOR(Ti,1,T) { LL A,B; int f; scanf("%lld%lld%d",&A,&B,&f); printf("Case #%d: %lld\n",Ti,solve(B,f)-solve(A-1,f)); } return 0; }