题意:
题目意思就是给你L到R区间,和一个数字K,然后让你求L到R区间之内满足最长上升子序列长度为K的数字有多少个;
比如就是上升子序列长为的数字

思路:

的状态应该包含长度、状态、以及题目的要求(刚开始没考虑到以后每组的答案受到前面答案的影响,没有多开一维数组存就错了)
最长上升子序列有个的解法,数组存最长上升子序列对应有哪些点,这不是它主要的作用,遍历时我们需要把出现在中可能性更大的点放进去,所以数组存的有些点不一定是最长上升子序列对应的点,但是数组的长度就是的长度。
考虑到中最多只有个数字,所以用将数组状压到二进制,表示没存这个数,表示存了这个数。用位运算模拟数组的操作,只是这里不能用,所以这里求复杂度其实是的。

注意前缀零是没用的,因为自然数没有前缀零

Code:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e3+7;
inline ll read() {
    ll s = 0, w = 1;
    char ch = getchar();
    while (ch < 48 || ch > 57) {
        if (ch == '-') w = -1;
        ch = getchar();
    }
    while (ch >= 48 && ch <= 57)
        s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar();
    return s * w;
}
ll dp[20][1<<10|1][11];
int digit[20],k;
inline int update(int x,int sum) {
    for(int i=x;i<10;++i) if((1<<i)&sum)
        return (sum^(1<<i)|(1<<x));
    return sum|(1<<x);
}
ll dfs(int len,int tot,bool zero,bool limit) {
    if(!len) {
        int cnt=0;
        while(tot) {
            if(tot&1) cnt+=1;
            tot>>=1;
        }
        return cnt==k;
    }
    if(!limit&&dp[len][tot][k]!=-1) return dp[len][tot][k];
    int endi=(limit?digit[len]:9);
    ll ans=0;
    for(int i=0,pos;i<=endi;++i) {
        ans+=dfs(len-1,zero&&(i==0)?0:update(i,tot),zero&&i==0,limit&&i==endi);
    }
    if(!limit) dp[len][tot][k]=ans;
    return ans;
}
ll solve(ll n) {
    int len=0;
    while(n) {
        digit[++len]=n%10;
        n/=10;
    }
    return dfs(len,0,true,true);
}
int main() {
    int t=read(),cas=0;
    memset(dp,-1,sizeof dp);
    ll l,r;
    while(t--) {
        l=read(),r=read(),k=read();
        printf("Case #%d: %lld\n",++cas,solve(r)-solve(l-1));
    }
    return 0;
}