2020牛客多校6 H

题意:

定义 (S(x)) 函数表示 (x) 的数位和,给定一个 (N),问有多少对 ((A,B) in 0 leq A leq B leq N) 满足 (S(A)>S(B))

题解:

数位 dp, 设 (dp[len][sum][limit1][limit2]) 表示当前 dfs 到第 (len) 位,数 (A) 与数 (B) 的差值为 (sum),数 (B) 的最高位限制状态为 (limit1),数 (A) 的最高位限制状态为 (limit2)

在 dfs 过程中,对于当前这一位用两个循环枚举数 (B) 与数 (A) 的取值,外层枚举 (B),内层枚举 (A)
第一层 (B) 的枚举上限 (i) 就是 最高位限制与否 的取值。
第二层上限 (j) 简单地考虑两种情况:
1.如果数 (A) 已经没有最高位限制就代表数 (A) 后面无论如何取都一定比数 (B) 小,所以上限设为 (9)
2.如果有最高位限制,则 (j) 应该小于等于 (i),这样就能保证 dfs 过程中数 (A) 永远小于等于 (B)
其它的就是数位 dp 的模板部分了。
最后递归结束,判断一下 (sum) 是否大于 (0)即可。为了避免越界可以将判断的基准变为 (1000)

#include <bits/stdc++.h>
using namespace std;
                
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define debug(x) cerr << #x << " is " << x << '
';
       
typedef long long LL;
typedef pair<int, int> pii;
             
const int N = 2e5 + 5, M = 1e6, P = 1e9 + 7;
 
int len, dp[105][2005][2][2];
string s;
  
int dfs(int g, int sum, int lim1, int lim2) {
  if (!g) {
    if (sum > 1000) return 1;
    return 0;
  }
  if (~dp[g][sum][lim1][lim2]) return dp[g][sum][lim1][lim2];
  int up1 = lim1 ? s[g - 1] - '0' : 9;
  int ans = 0;
  for (int i = 0; i <= up1; i++) {
    int up2 = lim2 ? i : 9;
    for (int j = 0; j <= up2; j++) {
      ans = (ans + dfs(g - 1, sum + j - i, lim1 && i == up1, lim2 && j == up2)) % P;
    }
  }
  return dp[g][sum][lim1][lim2] = ans;
}
 
int main() {
  ios::sync_with_stdio(false);
  cin.tie(0);
  cin >> s;
  reverse(s.begin(), s.end());
  int len = s.length();
  memset(dp, -1, sizeof dp);
  cout << dfs(len, 1000, 1, 1) << '
';
  return 0;
}
原文地址:https://www.cnblogs.com/ChaseNo1/p/13388601.html