https://ac.nowcoder.com/acm/contest/5671/H
题意
求(1 le A le B le N),满足(S(A)>S(B))的((A,B))个数
s是数码和
题解
数位dp,设(f[pos][dif][f1][f2])为确定了(pos-n)位,差为dif,边界情况为f1和f2的方案数,暴力枚举A,B下一位转移即可
数位 DP 的复杂度为 O(进制数 * 位数 + 进制数 * 新增状态数)
它并不像其他的记忆化搜索一样,搜索到最后复杂度会降低到 O(1) 直接返回。
即使最终再也没有新状态,其复杂度仍然为 O(进制数 * 位数)
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int p = 1e9 + 7;
int initial = 1050;
int digit[105];
int dp[105][2050][2][2];
int dfs(int pos, int dif, int f1, int f2) {
if (pos == 0) return dif > initial;
if (dp[pos][dif][f1][f2] != -1) return dp[pos][dif][f1][f2];
int sz = f1 ? digit[pos] : 9;
int ans = 0;
for (int i = 0; i <= sz; i++) {
int sz2 = f2 ? i : 9;
for (int j = 0; j <= sz2; j++) {
ans = (ans + dfs(pos - 1, dif + j - i, f1 && (i == sz), f2 && (j == sz2))) % p;
}
}
dp[pos][dif][f1][f2] = ans;
return ans;
}
char s[105];
int calc(char s[]) {
int len = strlen(s + 1);
for (int i = 1; i <= len; i++) {
digit[len - i + 1] = s[i] - '0';
}
return dfs(len, initial, 1, 1);
}
int main() {
memset(dp, -1, sizeof(dp));
scanf("%s", s + 1);
printf("%d
", calc(s));
return 0;
}