求a - b 的按每位值来最长lis长度为k的个数
当求lis时 每加入一个数看此时的lis中有没有数大于等于它且前一个数小于它,有的话将这个位置替换成这个数,没有的话把它填入到末尾 lis+1
所以dp[i][sym][len] 代表 推到第i位,此时组成状态为sym, 最后lis长度为len的方案数
注意处理前导0
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#define LL long long
using namespace std;
LL dp[21][1026][23];
LL l, x[100];
LL update(LL n, LL va)
{
for(int i = va; i<= 9; i++)
if(n & (1 << i)) return n ^ (1 << i) | (1 << va);
return n | (1 << va);
}
LL getNum(LL n)
{
int sum = 0;
while(n)
{
if(n & 1) sum++;
n >>= 1;
}
return sum;
}
LL dfs(LL i, bool e, LL pre, LL len, bool sym) //状态
{
if(i == -1) return getNum(pre) == len;
if(e && dp[i][pre][len] != -1) return dp[i][pre][len];
int Max = e ? 9 : x[i];
LL ans = 0;
for(int j = 0; j <= Max; j++)
ans += dfs(i - 1, !(!e && j == x[i]), sym||j? update(pre, j) : 0, len, sym || j);
if(e) dp[i][pre][len] = ans;
return ans;
}
LL cal(LL n, LL len)
{
l = 0;
while(n)
{
x[l++] = n % 10;
n /= 10;
}
return dfs(l - 1, 0, 0, len, 0);
}
int main()
{
memset(dp, -1, sizeof(dp));
int t, i1 = 1;
scanf("%d", &t);
while(t--)
{
LL a, b, k;
scanf("%I64d %I64d %I64d", &a, &b, &k);
printf("Case #%d: %I64d\n", i1++, cal(b, k) - cal(a - 1, k));
}
return 0;
}