Codeforces Round 962 (Div. 3) CDE

lulaalu·2024-07-27 20:25·48 次阅读

Codeforces Round 962 (Div. 3) CDE

时间:2024-07-27

C. Sort#

原题:C. Sort

标签:前缀和

题意#

给定字符串a,b

定义 sorted(a[l..r]) 表示将a的lr区间排序为有序

有q次询问,每次给出区间l,r,要求通过操作使sorted(a[l..r])==sorted(b[l..r])

操作为将ai变成需要的任意字符,求最少次数

思路#

一开始由于是div3,尝试了一下是不是暴力

暴力的过法就是,每次询问都遍历一遍两个字符串的区间,然后比较各个字符的数量

比如说在a中有3个‘a’,2个’b‘,在b中有2个‘a‘3个’b‘,那么只需要将一个’b‘变成’a‘就可以

但是实际上不需要看’b‘,就看’a‘差了几个就行,只考虑补足数量不足的字符

暴力法显然过不去,然后再回看这种数量关系,很容易想到前缀和

而且每类字符单独考虑,就用类似 sum[N][26] 的形式,存储前 i 个字符中 j+a 的数量

代码#

Copy
const int N = 2e5 + 10; int len, q; string s1, s2; vector<int> sum1[N]; vector<int> sum2[N]; void build() { for (int i = 0; i <= len; i++) { for (int j = 0; j < 26; j++) { sum1[i][j] = 0; sum2[i][j] = 0; } } for (int i = 0; i < len; i++) { sum1[i + 1][s1[i] - 'a']++; sum2[i + 1][s2[i] - 'a']++; } for (int i = 2; i <= len; i++) { for (int j = 0; j < 26; j++) { sum1[i][j] += sum1[i - 1][j]; sum2[i][j] += sum2[i - 1][j]; } } } void solve() { cin >> len >> q; cin >> s1 >> s2; build(); int l, r; for (int i = 0; i < q; i++) { cin >> l >> r; int ans = 0; for (int j = 0; j < 26; j++) { int t = (sum1[r][j] - sum1[l - 1][j]) - (sum2[r][j] - sum2[l - 1][j]); if (t < 0) ans += t; } cout << -ans << endl; } } signed main() { for (int i = 0; i <= N - 1; i++) { sum1[i].resize(26, 0); sum2[i].resize(26, 0); } int t = 1; cin >> t; while (t--) solve(); return 0; }

D. Fun#

原题:D. Fun

标签:枚举

题意#

给定两个整数 n 和 x ,要求 ab+ac+bcn 和 a+b+cx

输出满足条件的三元组 (a,b,c) 的组数

思路#

本题在经过一系列找规律后,发现根本找不到规律。。。

找不到规律就先开始考虑暴力枚举

本题如果枚举三个数是会超时的,那么看看能不能枚举两个数

本题给的两个限定条件 nx ,要理清思路,假如确定了两个值,第三个值是能直接算出来的

如果是确定 ab ,那么对于 c ,首先 cxab ,同时 c(nab)/(a+b)

代码#

核心代码

Copy
for (int a = 1; a <= x; a++) for (int b = 1; a * b <= n && a + b < x; b++) ans += min(x - a - b, (n - a * b) / (a + b));

E. Decode#

原题:E. Decode

标签:字符串、前缀和

题意#

给定01串 s,对与任意的区间lr,在lr中再选取任意x<y,要求s[x...y]中的01个数相等

答案对1e9+7取余

思路#

  1. 出现这种数量相等的情况,一般考虑能不能用前缀和处理一下,让01的数量通过加1减1来抵消

1100111001

Copy
index 1 2 3 4 5 6 7 8 9 10 1 1 0 0 1 1 1 0 0 1 sum 1 2 1 0 1 2 3 2 1 2

以下标2到3为x,y,那么就可以在 O(1) 时间得出l和r的种类,l[1,x],r[y,10]

  1. 那么现在的问题转变成了要怎么找到所有这样的x和y呢?

显然通过sum,对于l到r,sum[r]==sum[l1]

所以将sum值相同的下标存储在一起

  1. 现在的问题又转化为,该怎么快速的将答案求出来呢

在这个例子中,对于sum=1有以下下标:1 3 5 9

我们先手算一下答案:

1(103+1)+1(105+1)+1(109+1)+3(105+1)+3(109+1)+5(109+1)

答案不是重点,重点是式子,我们转化成如下式子:

1(109+1)+3(109+1)+5(109+1)

1(105+1)+3(105+1)

1(103+1)

相当于是,用一个变量 cur 存储需要用到的 l ,比如对于3,需要用1,对于5,需要用1+3,

流程就是,在处理完小的 lr 后,将 r 存储到 cur 中,这样 cur 存的就是1+3

cur5 算完后,再将 5 存储到 cur 中,然后是 cur9

代码#

说明,由于我是用数组处理,所以所有负数转变成正数了

可以用map处理

Copy
#include <bits/stdc++.h> using namespace std; #define YES "Yes" #define NO "No" #define F first #define S second #define int long long #define ull unsigned long long #define endl "\n" #define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); #define rep(i, j, k) for (i = (j); i < (k); i++) #define all(x) x.begin(), x.end() #define vi vector<int> typedef pair<int, int> pii; const int MOD = 1000000007; const int N = 2e5 + 10; int ii, jj, kk; string s; int sum[N] = {0}; vector<int> v[2 * N]; void solve() { cin >> s; int len = s.length(); for (int i = 0; i < len; i++) { if (s[i] == '1') sum[i + 1] = sum[i] + 1; else sum[i + 1] = sum[i] - 1; } // 由于有负数的原因,将每个值+len,保证是正数 for (int i = 0; i <= len; i++) v[sum[i] + len].push_back(i); int ans = 0; for (int i = 0; i <= 2 * len; i++) { int cur = 0; for (int vv : v[i]) { ans = (ans + ((len + 1 - vv) * cur)) % MOD; cur = (cur + 1 + vv) % MOD; } } cout << ans << endl; for (int i = 0; i <= 2 * len; i++) v[i].clear(); } signed main() { IOS; int t = 1; cin >> t; while (t--) solve(); return 0; }
posted @   lulaalu  阅读(48)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
点击右上角即可分享
微信分享提示
目录