XHXJ’s LIS
题意
题目意思就是给你 l 到 r 区间和一个数字 k,求 l 到 r 区间之内满足最长上升子序列长度为K的数字有多少个。
题解
在网上找到的代码,加入了注释
dp[pos][sta][flag]:pos 对应位置,sta 计算递增个数
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
#define ll long long
ll dp[25][1 << 10][11];
int bit[25];
int k;
//运用 LIS 问题的 nlogn 思想进行更新状态,if 对应位上为 1 ,证明LIS数组上有这个数
int getNewSta(int sta, int num) {
//操作就是第一个 >= num 的地方取代为 num
for (int i = num; i <= 9; i++) {
//判断一个数字 s 二进制下第 i+1 位是不是等于 1
//第 i+1 位变为 0,num+1 位变为1
if (sta & (1 << i)) {
return (sta ^ (1 << i)) | (1 << num);
}
}
return sta | (1 << num);//将sta的num数字对应的搞为1
}
//查看上升个数
int getValSta(int Sta) {
int tot = 0;
for (int i = 0; i < 10; ++i) {
if (Sta & (1 << i)) {
++tot;
}
}
return tot;
}
ll dfs(int pos, int state, int flag) {
if (pos <= 0) {
return getValSta(state) == k;
}
if (!flag && dp[pos][state][k] != -1) {
return dp[pos][state][k];
}
ll ans = 0;
int end = flag ? bit[pos] : 9;
//主要判断过程
for (int i = 0; i <= end; i++) {
ans += dfs(pos - 1, (state == 0 && i == 0) ? 0 : getNewSta(state, i), flag && i == end);
}
if (!flag) {
dp[pos][state][k] = ans;
}
return ans;
}
ll cal(ll n) {
ll x = n;
int num = 0;
while (x) {
bit[++num] = x % 10;
x /= 10;
}
return dfs(num, 0, 1);
}
int main() {
int t;
ll l, r;
memset(dp, -1, sizeof(dp));
scanf("%d", &t);
int num = 0;
while (t--) {
scanf("%lld%lld%d", &l, &r, &k);
printf("Case #%d: ", ++num);
printf("%lld\n", cal(r) - cal(l - 1));
}
return 0;
}