Atcoder-ABC154-EF 题解

Atcoder题解汇总

ABC 154

E. Almost Everywhere Zero (简单数位DP)

题意

1 n 中, 非零数位恰好有 k 个的数字个数

数据范围
1n10100

思路

  • 一眼数位DP, 常规状态记录, dp[i][j] 搜到了第 i 位, 非零个数位 j 的数字个数

Solution

#include<bits/stdc++.h> typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> PII; typedef std::pair<ll, ll> PLL; typedef double db; #define arr(x) (x).begin(),(x).end() #define x first #define y second #define pb push_back #define mkp make_pair #define endl "\n" using namespace std; const int N = 110; ll dp[N][4], a[N]; int k; ll dfs(int pos, int cnt, bool lead, bool limit){ if(cnt > k) return 0; if(pos == -1) return cnt == k; // 最后判断符合条件需要严格 k 个数 if(!limit && !lead && dp[pos][cnt] != -1) return dp[pos][cnt]; int up = limit ? a[pos] : 9; if(cnt == k) up = 0; ll res = 0; for(int i = 0; i <= up; i++){ int t = (i != 0); res += dfs(pos - 1, cnt + t, lead && i == 0, limit && i == a[pos]); } if(!limit && !lead) dp[pos][cnt] = res; return res; } int main(){ ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); string s; cin >> s >> k; int pos = 0; memset(dp, -1, sizeof dp); for(int i = s.size() - 1; ~i; i--) a[pos++] = s[i] - '0'; cout << dfs(pos - 1, 0, true, true) << endl; return 0; }

F. Many Many Paths (组合数)

题意

二维平面, 输入两个点的坐标 (r1,c1),(r2,c2), 求从 (0,0) 到两点之间矩形区域内的点的路径数总和, 设 f(i,j) 为到 (i,j) 路径数, 则求 Σr1ir2,c1jc2f(i,j) 大小

数据范围
1r1r2106
1c1c2106

思路

  • 用二维前缀和容斥的思想, 如果我们知道 g(r,c) 代表 (0,0)(r,c) 的方案和, 则答案等于 g(r2,c2)g(r11,c2)g(r2,c11)+g(r11,c11)
  • 明显可知 f(i,j)=Ci+ji, 则需要求 Σi=r1r2Σj=c1c2Ci+jj, 考虑如何求单个 g(r,c) 就可以解决此题
  • 即便预处理逆元和阶乘, 也需要 O(n2) 的复杂度, 考虑优化计算
  • 有公式 Cm+r+1r=Σi=0rCm+ii , 在此题意义便是 f(r,0)+f(r,1)+...+f(r,c)=f(r+1,c)
  • 因此内层循环被优化掉, 具体推导可以见代码注释部分, O(n) 求解各个 g(r,c)

Solution

#include<bits/stdc++.h> typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> PII; typedef std::pair<ll, ll> PLL; typedef double db; #define arr(x) (x).begin(),(x).end() #define x first #define y second #define pb push_back #define mkp make_pair #define endl "\n" using namespace std; const int mod = 1e9 + 7; const int N = 2e6; ll fact[N + 10], f1[N], f2[N], g1[N], g2[N]; ll inv[N + 10]; ll qmi(ll a, ll k, int mod) { ll res = 1; while (k) { if (k & 1) res = res * a % mod; a = a * a % mod; k >>= 1; } return res; } // ans = g(r2, c2) - g(r2, c1 - 1) - g(r1 - 1, c2) + g(r1 - 1, c1 - 1); // g(r, c) = f(0,0) +...+ f(0, c) + ... + f(r,0) + ... + f(r, c); // g(r, c) = f(1,c) + f(2, c) + f(3,c) +...+ f(r+1,c) // f(r,c) = (r+c)! * inv[r] * inv[c]; ll C(int a, int b) { return fact[a] * inv[b] % mod * inv[a - b] % mod; } int main(){ ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); int r1, r2, c1, c2; cin >> r1 >> c1 >> r2 >> c2; fact[0] = inv[0] = 1; for (int i = 1; i <= N + 5; i++) { fact[i] = 1ll * fact[i - 1] * i % mod; inv[i] = inv[i - 1] * qmi(i, mod - 2, mod) % mod; } ll g1 = 1, g2 = 1, g3 = 1, g4 = 1; for (int i = 1; i <= r2 + 1; i++) { g1 = (g1 + C(i + c2, c2)) % mod; g2 = (g2 + C(i + c1 - 1, c1 - 1)) % mod; } for (int i = 1; i <= r1; i++) { g3 = (g3 + C(i + c2, c2)) % mod; g4 = (g4 + C(i + c1 - 1, c1 - 1)) % mod; } cout << (g1 - g2 - g3 + g4 + mod) % mod << endl; return 0; }

__EOF__

本文作者Roshin
本文链接https://www.cnblogs.com/Roshin/p/ABC154.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   Roshin  阅读(59)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· Apache Tomcat RCE漏洞复现(CVE-2025-24813)
-->
点击右上角即可分享
微信分享提示