- 分享
其他OJ题解
- @ 2025-12-11 14:15:07
其他OJ题解
5 comments
-
33DAI 33 LV 9 (1/1) SU @ 2026-1-18 16:18:31
[R46D]四元组
#include <bits/stdc++.h> using namespace std; int n; int a[2000 + 5]; // 右边的每种和出现了几次 int cnt[2000 + 2000 + 5]; int main() { ios::sync_with_stdio(false); cin.tie(0); cin >> n; for (int i = 1; i <= n; i++) cin >> a[i]; // 初始所有数都在右边 for (int i = 1; i <= n; i++) for (int j = i + 1; j <= n; j++) cnt[a[i] + a[j]]++; // 枚举 a[i] 丢到左边带来的新贡献 long long ans = 0; for (int i = 1; i <= n; i++) { // 把 a[i] 对右边 cnt 的贡献消除 for (int j = i + 1; j <= n; j++) cnt[a[i] + a[j]]--; // 用 a[i] 与左边的元素组合,统计产生的贡献 for (int j = 1; j <= i - 1; j++) ans += cnt[a[i] + a[j]]; } cout << ans; return 0; } -
@ 2026-1-18 15:34:17
[R46E]机器
没有调用机器,直接差分数组维护所有区间修改
#include <bits/stdc++.h> #define int long long using namespace std; const int MAXN = 200000; const int MOD = 1'000'000'000 + 7; int n, m, q; struct Mac { int typ, l, r, x; }; Mac mac[MAXN + 5]; int cnt[MAXN + 5]; // 每台机器被调用的次数 int num[MAXN + 5]; // 每个盒子的糖果数量 int d[MAXN + 5]; // 差分数组 signed main() { ios::sync_with_stdio(false); cin.tie(0); cin >> n >> m >> q; for (int i = 1; i <= m; i++) { cin >> mac[i].typ; if (mac[i].typ == 1) cin >> mac[i].l >> mac[i].r >> mac[i].x; if (mac[i].typ == 2) cin >> mac[i].l >> mac[i].r; } // q 次直接调用 while (q--) { int l, r; cin >> l >> r; d[l]++, d[r + 1]--; } // 还原出每台机器被直接调用的次数 for (int i = 1; i <= m; i++) cnt[i] = cnt[i - 1] + d[i]; // 清空差分数组 for (int i = 1; i <= m + 1; i++) d[i] = 0; // 子任务 1,每台机器的使用次数已经确定 for (int i = 1; i <= m; i++) { if (mac[i].typ == 2) continue; d[mac[i].l] = (d[mac[i].l] + mac[i].x * cnt[i] % MOD) % MOD; d[mac[i].r + 1] = (d[mac[i].r + 1] - mac[i].x * cnt[i] % MOD) % MOD; } for (int i = 1; i <= n; i++) num[i] = ((num[i - 1] + d[i]) % MOD + MOD) % MOD; for (int i = 1; i <= n; i++) cout << num[i] << " "; cout << "\n"; return 0; }用树状数组维护机器之间的调用
实际上倒着做差分数组也可以。
#include <bits/stdc++.h> #define int long long using namespace std; const int MAXN = 200000; const int MOD = 1'000'000'000 + 7; int n, m, q; struct Mac { int typ, l, r, x; }; Mac mac[MAXN + 5]; int cnt[MAXN + 5]; // 每台机器被调用的次数 int num[MAXN + 5]; // 每个盒子的糖果数量 int d[MAXN + 5]; // 差分数组 // 树状数组来实现机器的调用次数 int lowbit(int x) { return x & -x; } int t[MAXN + 5]; void update(int x, int y) { for (int i = x; i <= m; i += lowbit(i)) t[i] = (t[i] + y) % MOD; } int query(int x) { int res = 0; for (int i = x; i >= 1; i -= lowbit(i)) res = (res + t[i]) % MOD; return res; } signed main() { ios::sync_with_stdio(false); cin.tie(0); cin >> n >> m >> q; for (int i = 1; i <= m; i++) { cin >> mac[i].typ; if (mac[i].typ == 1) cin >> mac[i].l >> mac[i].r >> mac[i].x; if (mac[i].typ == 2) cin >> mac[i].l >> mac[i].r; } // q 次直接调用 while (q--) { int l, r; cin >> l >> r; update(l, 1); update(r + 1, -1); } // 处理机器之间的调用 for (int i = m; i >= 1; i--) { cnt[i] = query(i); if (mac[i].typ == 2) { update(mac[i].l, cnt[i]); update(mac[i].r + 1, -cnt[i]); } } // 清空差分数组 for (int i = 1; i <= m + 1; i++) d[i] = 0; // 子任务 1,每台机器的使用次数已经确定 for (int i = 1; i <= m; i++) { if (mac[i].typ == 2) continue; d[mac[i].l] = (d[mac[i].l] + mac[i].x * cnt[i] % MOD) % MOD; d[mac[i].r + 1] = (d[mac[i].r + 1] - mac[i].x * cnt[i] % MOD) % MOD; } for (int i = 1; i <= n; i++) num[i] = ((num[i - 1] + d[i]) % MOD + MOD) % MOD; for (int i = 1; i <= n; i++) cout << num[i] << " "; cout << "\n"; return 0; } -
@ 2026-1-2 16:53:43
#include <bits/stdc++.h> using namespace std; struct Node { // 位置,是否有青蛙 int x, y, z; }; int n, m; char g[1005][1005]; queue<Node> q; int dis[1005][1005][2]; bool vis[1005][1005][2]; int dx[] = {0, 0, 1, -1}; int dy[] = {1, -1, 0, 0}; int main() { cin >> n >> m; for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) cin >> g[i][j]; q.push({1, 1, 0}); dis[1][1][0] = 0; vis[1][1][0] = true; while (!q.empty()) { Node now = q.front(); q.pop(); // 捡青蛙 if (g[now.x][now.y] == 'F' && now.z == 0) { int x = now.x; int y = now.y; int z = 1; if (!vis[x][y][z]) { q.push({x, y, z}); vis[x][y][z] = true; dis[x][y][z] = dis[now.x][now.y][now.z] + 1; } } // 手拿青蛙在树上 if (g[now.x][now.y] == '#' && now.z == 1) { int x = now.x; int y = now.y; int z = 0; if (!vis[x][y][z]) { q.push({x, y, z}); vis[x][y][z] = true; dis[x][y][z] = dis[now.x][now.y][now.z] + 1; } // 此时不能走四个方向 continue; } // 四个方向走 for (int i = 0; i < 4; i++) { int x = now.x + dx[i]; int y = now.y + dy[i]; int z = now.z; if (vis[x][y][z]) continue; if (x < 1 || x > n || y < 1 || y > m) continue; if (g[x][y] == '#' && z == 0) continue; q.push({x, y, z}); vis[x][y][z] = true; dis[x][y][z] = dis[now.x][now.y][now.z] + 1; } } int ans; if (vis[n][m][0] && !vis[n][m][1]) ans = dis[n][m][0]; else if (!vis[n][m][0] && vis[n][m][1]) ans = dis[n][m][1]; else ans = min(dis[n][m][0], dis[n][m][1]); cout << ans << "\n"; return 0; } -
@ 2025-12-20 10:51:28
#include <bits/stdc++.h> #define int long long using namespace std; const int MOD = 998244353; int n; signed main() { ios::sync_with_stdio(false); cin.tie(0); cin >> n; int l, r; l = r = 0; int now, num; // 当前等级,数量 now = 1, num = 1; int ans = 0; while (r < n) { // 用不完 num 个的话,能用几个是几个 if (r + num > n) num = n - r; l = r + 1; r = l + num - 1; // l~r 这些 now 等级的 int sum; // l~r 的区间和 if ((l + r) % 2 == 0) sum = ((l + r) / 2 % MOD) * (num % MOD) % MOD; else sum = ((l + r) % MOD) * ((num / 2) % MOD) % MOD; ans = (ans + now % MOD * sum % MOD) % MOD; // 换成下一个等级 now++, num *= 2; } cout << ans * 2 % MOD << "\n"; return 0; }#include <bits/stdc++.h> #define int long long using namespace std; int n, m; int a[4005], b[4005], p[4005]; int w[4005]; int dp[4005][4005]; signed main() { ios::sync_with_stdio(false); cin.tie(0); cin >> n >> m; for (int i = 1; i <= n; i++) cin >> a[i]; for (int i = 1; i <= m; i++) cin >> b[i]; for (int i = 2; i <= n; i++) cin >> p[i]; w[1] = 1; for (int i = 2; i <= n; i++) w[i] = w[p[i]] + i; for (int i = 1; i <= n; i++) for (int j = 0; j <= m; j++) { dp[i][j] = 0; // 不替换 a[i] dp[i][j] = max(dp[i][j], dp[i - 1][j] + a[i] * w[i]); if (j == 0) continue; // 用 b[j] 替换 a[i] dp[i][j] = max(dp[i][j], dp[i - 1][j - 1] + b[j] * w[i]); // 用 b[<j] 替换 a[i] dp[i][j] = max(dp[i][j], dp[i][j - 1]); } cout << dp[n][m]; return 0; } -
@ 2025-12-11 14:16:37
【HT-089-Div.4】核桃新手组周赛
https://htoj.com.cn/cpp/oj/contest/detail?cid=22589816735488
P10983 替换
特殊性质 20 分
#include<bits/stdc++.h> using namespace std; int main(){ int T; cin>>T; while(T--){ string s,t; cin>>s>>t; if(s.size()<t.size()) cout<<"NO\n"; else cout<<"YES\n"; } return 0; }子串性质,暴力枚举 40 分
#include<bits/stdc++.h> using namespace std; string s,t; // 检查 s[l]~s[r] 是不是 t[0]~t[t.size()-1] bool check(int l,int r){ for(int i=l;i<=r;i++) if(s[i]!='?' && s[i]!=t[i-l]) return false; return true; } void work(){ cin>>s>>t; // 希望 t 是 s 的某个子串 if(s.size()<t.size()) { cout<<"NO\n"; return; } for(int i=0;i+t.size()-1<s.size();i++){ // 如果 t 是 s[i]~s[i+t.size()-1] 就找到了 if(check(i,i+t.size()-1)) { cout<<"YES\n"; return; } } cout<<"NO\n"; return; } int main(){ int T; cin>>T; while(T--) work(); return 0; }正解
容易发现问号能用上就用,不然就浪费了。
#include<bits/stdc++.h> using namespace std; string s,t; void work(){ cin>>s>>t; // 希望 t 是 s 的某个子序列 for(int i=0,j=0;i<t.size();i++){ // 在 s[j]~末尾寻找 t[i] while(j+1<s.size() && s[j]!='?' && s[j]!=t[i]) j++; // 1. 停在匹配的位置 // 2. 找不到的时候停在最后一位 if(s[j]=='?' || s[j]==t[i]) j++; else { cout<<"NO\n"; return; } } cout<<"YES\n"; return; } int main(){ int T; cin>>T; while(T--) work(); return 0; }P10984 爱好
处理 R=1,意外拿到 40 分
#include<bits/stdc++.h> using namespace std; int r,c; string s; // cnt[i][1]: s[0]~s[i] 有几个 A // cnt[i][2]: s[0]~s[i] 有几个 AB // cnt[i][3]: s[0]~s[i] 有几个 ABC long long cnt[1005][4]; int main(){ cin>>r>>c; cin>>s; // 在 s 里面找 ABC cnt[0][1]=cnt[0][2]=cnt[0][3]=0; if(s[0]=='A') cnt[0][1]=1; for(int i=1;i<s.size();i++) { // 先继承之前的数量 cnt[i][1]=cnt[i-1][1]; cnt[i][2]=cnt[i-1][2]; cnt[i][3]=cnt[i-1][3]; // 看一下这一位多了几个 if(s[i]=='A') cnt[i][1]++; // 之前几个 A 这里就有几个 AB if(s[i]=='B') cnt[i][2]+=cnt[i][1]; // 之前几个 AB 这里就有几个 ABC if(s[i]=='C') cnt[i][3]+=cnt[i][2]; } cout<<cnt[s.size()-1][3]; return 0; }每一行每一列都按照40分的代码处理
#include<bits/stdc++.h> using namespace std; int r,c; // cnt[i][1]: s[0]~s[i] 有几个 A // cnt[i][2]: s[0]~s[i] 有几个 AB // cnt[i][3]: s[0]~s[i] 有几个 ABC string s; long long cnt[1005][4]; // 返回字符串 s 里面有几个 ABC int cal(){ // 在 s 里面找 ABC cnt[0][1]=cnt[0][2]=cnt[0][3]=0; if(s[0]=='A') cnt[0][1]=1; for(int i=1;i<s.size();i++) { // 先继承之前的数量 cnt[i][1]=cnt[i-1][1]; cnt[i][2]=cnt[i-1][2]; cnt[i][3]=cnt[i-1][3]; // 看一下这一位多了几个 if(s[i]=='A') cnt[i][1]++; // 之前几个 A 这里就有几个 AB if(s[i]=='B') cnt[i][2]+=cnt[i][1]; // 之前几个 AB 这里就有几个 ABC if(s[i]=='C') cnt[i][3]+=cnt[i][2]; } return cnt[s.size()-1][3]; } char g[1005][1005]; int main(){ cin>>r>>c; for(int i=1;i<=r;i++) for(int j=1;j<=c;j++) cin>>g[i][j]; long long ans = 0; // 每一行算一下 for(int i=1;i<=r;i++){ s=""; for(int j=1;j<=c;j++) s+=g[i][j]; ans+=cal(); } // 每一列算一下 for(int j=1;j<=c;j++) { s=""; for(int i=1;i<=r;i++) s+=g[i][j]; ans+=cal(); } cout<<ans; return 0; }
- 1