2020牛客多校6 H - Harmony Pairs

题意:

定义 \(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 << '\n';
       
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) << '\n';
  return 0;
}
posted @ 2020-07-27 23:46  Chase。  阅读(142)  评论(0编辑  收藏  举报