链接:
https://vjudge.net/problem/HDU-4352
题意:
a 到 b中一个数组成递增子序列长度等于k的数的个数
思路:
因为只有10个数,使用二进制维护一个递增序列,每次更新在注释写了。
然后正常的数位DP,
Dp(i, j, k),i是位置,j是当前的递增状态,k是长度。
考虑一下前缀0,重置状态
代码:
#include<bits/stdc++.h> using namespace std; typedef long long LL; const int MOD = 1e9+7; const int MAXN = 1e6+10; LL F[30][1<<10][11]; int dig[30]; LL a, b; int k; int Upd(int x, int s) { //x表示当前值,s表示递增序列 for (int i = x;i < 10;i++) { if (s & (1<<i)) return (s ^ (1 << i)) | (1 << x);//找到一个比当前值大的,换成较小的 } return s | (1 << x); } int Len(int x) { int cnt = 0; while(x) { if (x&1) cnt++; x >>= 1; } return cnt; } LL Dfs(int pos, int sta, bool zer, bool lim) { if (pos == -1) return Len(sta) == k; if (!lim && F[pos][sta][k] != -1) return F[pos][sta][k]; int up = lim ? dig[pos] : 9; LL cnt = 0; for (int i = 0;i <= up;i++) cnt += Dfs(pos-1, (zer && i == 0) ? 0 : Upd(i, sta), zer && (i == 0), lim && (i == up)); if (!lim) F[pos][sta][k] = cnt; return cnt; } LL Solve(LL x) { int p = 0; while(x) { dig[p++] = x%10; x /= 10; } return Dfs(p-1, 0, true, true); } int main() { // freopen("test.in", "r", stdin); memset(F, -1, sizeof(F)); int t, cnt = 0; scanf("%d", &t); while(t--) { scanf("%lld%lld%d", &a, &b, &k); printf("Case #%d: %lld\n", ++cnt, Solve(b)-Solve(a-1)); } return 0; }