Codeforces Round (Div.3) C.Sort (前缀和的应用)
原题:
time limit per test:5 seconds
memory limit per test:256 megabytes
You are given two strings a and b of length n. Then, you are (forced against your will) to answer q queries.
For each query, you are given a range bounded by l and r. In one operation, you can choose an integer i (l≤i≤r) and set ai=x where x is any character you desire. Output the minimum number of operations you must perform such that sorted(a[l..r])=sorted(b[l..r]). The operations you perform on one query does not affect other queries.
For an arbitrary string c, sorted(c[l..r]) denotes the substring consisting of characters cl,cl+1,...,cr sorted in lexicographical order.
Input
The first line contains t (1≤t≤1000) – the number of test cases.
The first line of each test case contains two integers nn and q (1≤n,q≤2⋅10^5) – the length of both strings and the number of queries.
The following line contains a of length n. It is guaranteed aa only contains lowercase latin letters.
The following line contains b of length n. It is guaranteed bb only contains lowercase latin letters.
The following q lines contain two integers l and r (1≤l≤r≤n) – the range of the query.
It is guaranteed the sum of n and q over all test cases does not exceed 2⋅10^5.
Output
For each query, output an integer, the minimum number of operations you need to perform in a new line.
翻译:
问题描述:
你被给定了两个长度为 n
的字符串 a
和 b
。然后,你需要(虽然是被迫的)回答 q
个查询。
对于每个查询,你会得到一个由 l
和 r
确定的范围。在一个操作中,你可以选择一个整数 i
(l ≤ i ≤ r
)并将 a[i]
设置为你希望的任何字符。输出你必须执行的最小操作次数,以确保 sorted(a[l..r]) = sorted(b[l..r])
。你对一个查询执行的操作不会影响其他查询。
对于任意字符串 c
,sorted(c[l..r])
表示在 c[l]
到 c[r]
的子字符串中按字典序排序后的子字符串。
输入:
第一行包含 t
(1 ≤ t ≤ 1000
)—— 测试用例的数量。
每个测试用例的第一行包含两个整数 n
和 q
(1 ≤ n, q ≤ 2⋅10^5
)—— 两个字符串的长度和查询的数量。
接下来一行包含长度为 n
的字符串 a
。字符串 a
只包含小写字母。
接下来一行包含长度为 n
的字符串 b
。字符串 b
只包含小写字母。
接下来 q
行,每行包含两个整数 l
和 r
(1 ≤ l ≤ r ≤ n
)—— 查询的范围。
保证所有测试用例中 n
和 q
的总和不超过 2⋅10^5
。
输出:
对于每个查询,输出一个整数,表示你需要执行的最小操作次数,每个查询输出一行。
Cf的题属于是想到就出结果,想不到就卡死,没有很多的模板可以套用,必须要先观察,千万不要上来就暴力,很可能连签到都过不去哦
观察发现,这道题其实就是求在一个区间当中,两个字符串有多少个字符不同的数量,那可以假设一下,如果暴力来敲,先截取[l,r]的字符串,然后排序,然后去遍历一遍看有多少不同
如果是这样想基本就陷入到坑里面出不来了,因为的话按照字典序排序之后,你没办法要求两个字符串中相同的字符的字符位置一一对应,不同的一一对应,是有这种情况的,那么在看题目本身的需求,就是求有多少不同的个数,那其实对每个字符串求前缀和,记录第i个位置的26字母分别出现的次数,然后在给出区间之后在去对比前缀和中26字母数量的差异,相同就不用管,不同就加上不同的个数,最后除以2(因为两个字符串都加了一遍)
代码:
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>
using namespace std;
void solve() {
int n, q;
cin >> n >> q;
vector<vector<int>> pre1(n + 1,vector<int>(26,0));
vector<vector<int>> pre2(n + 1,vector<int>(26,0));
for(int i = 1;i <= n;i ++){
char ch;
cin >> ch;
pre1[i][ch - 'a'] ++;
for(int j = 0;j < 26;j ++){
pre1[i][j] += pre1[i - 1][j];
}
}
for(int i = 1;i <= n;i ++){
char ch;
cin >> ch;
pre2[i][ch - 'a'] ++;
for(int j = 0;j < 26;j ++){
pre2[i][j] += pre2[i - 1][j];
}
}
while(q --){
int l,r;
int res = 0;
cin >> l >> r;
for(int i = 0;i < 26;i ++){
int A = pre1[r][i] - pre1[l - 1][i];
int B = pre2[r][i] - pre2[l - 1][i];
res += abs(A - B);
}
cout << res / 2 << endl;
}
}
int main() {
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}
加油