C: 首先我们要看到比较明显的一点那就是c的值最大40,这意味着我们可以暴力回退:
是一道比较注意细节的模拟题
#include<iostream>
#include<string>
#include<algorithm>
#include<cstring>
using namespace std;
#define int long long
const int maxn = 2e5 + 10;
int a[maxn], n, m,q;
int sum[maxn];
char s[maxn];
pair<int, int>p[maxn];
void solve()
{
cin >> n >> m >> q;
sum[1] = n;
cin >> s+1;
p[0].first = 1, p[0].second = n;
for (int i = 1; i <= m; i++){
cin >> p[i].first >> p[i].second;
sum[i + 1] = sum[i] + p[i].second - p[i].first+1;
}
while (q--)
{
int t;
cin >> t;
int now = m+1;
while (now!=1)//模拟回退过程,一直回退到初始的区间
{
if (t <=sum[now - 1])
{
now--;
}
else
{
int now1 = t - sum[now - 1];
t = p[now - 1].first + now1-1;
now--;
}
}
cout << s[t] << endl;
}
}
signed main(){
int t=1;
cin >> t;
while (t--){
solve();
}
}
D: 我们将其分为不同的01串,可以确定的一点是,假如这个串数量大于1,那这个区间就可以任意将左右两边进行吞并和吐出:001100->011110,这个条件是确保左右不嫩将左右两边区间进行吞并,所以再保证0101区间的情况下,所以我们再保证01区间一样的前提下再查找最小操作次数:
#include<iostream>
#include<string>
#include<algorithm>
#include<cstring>
using namespace std;
#define int long long
const int maxn = 2e5 + 10;
int a[maxn], n, m,q;
int sum[maxn];
char s[maxn];
string s1, s2;
int cnt[maxn], cnt2[maxn];
void solve()
{
cin >> n;
cin >> s1 >> s2;
if (s1[0] != s2[0] || s1[n - 1] != s2[n - 1])//确保是一眼的01交替区间
{
cout << -1 << endl;
return;
}
int len1 = 1, len2 = 1;
cnt[0] = 0, cnt2[0] = 0;
cnt[1] = 1, cnt2[1] = 1;
for (int i = 1; i < n; i++){
if (s1[i] == s1[i - 1])
{
cnt[len1]++;
}
else
{
cnt[++len1] = 1;
}
}
for (int i = 1; i < n; i++) {
if (s2[i] == s2[i - 1])
{
cnt2[len2]++;
}
else
{
cnt2[++len2] = 1;
}
}
if (len1 != len2)
{
cout << -1 << endl;
}
else
{
int ans = 0;
for (int i = 1; i <len1; i++){//模拟过程
if (cnt[i] < cnt2[i]){
ans += abs(cnt[i] - cnt2[i]);
cnt[i + 1] -= abs(cnt[i] - cnt2[i]);
}
else if(cnt[i]>cnt2[i])
{
cnt[i + 1] += abs(cnt[i] - cnt2[i]);
ans += abs(cnt[i] - cnt2[i]);
}
}
cout << ans << endl;
}
}
signed main(){
int t=1;
cin >> t;
while (t--){
solve();
}
}
E:
我们先将其正确维护后 找最左边的1的位置就是答案,一般是套二分来查找,我找到了一篇直接跑线段树的题解,虽然速度比较慢
Codeforces Round #807 (Div. 2) A - E - 哔哩哔哩 (bilibili.com)
然后就是修改,假如cnt[a[x]]=1,我们就将其删掉就好了,假如不是,我们要从这个点出发,找到其右边最近的1,并将这些点均翻转:
#include<iostream>
#include<algorithm>
using namespace std;
#define int long long
const int maxn = 3e5 + 10;
int n, m, a[maxn], cnt[maxn];
struct node
{
int l, r;
int sum;
int rev;
}tree[maxn<<2];
void pushup(int rt)
{
tree[rt].sum = tree[rt << 1].sum + tree[rt << 1 | 1].sum;
}
void pushdown(int rt)
{
if (tree[rt].rev)
{
tree[rt << 1].sum = tree[rt << 1].r - tree[rt << 1].l + 1 - tree[rt << 1].sum;
tree[rt << 1|1].sum = tree[rt << 1|1].r - tree[rt << 1|1].l + 1 - tree[rt << 1|1].sum;
tree[rt << 1].rev ^= 1;
tree[rt << 1 | 1].rev ^= 1;
tree[rt].rev = 0;
}
}
void build(int rt, int l, int r)
{
tree[rt].l = l, tree[rt].r = r;
if (l == r)
{
tree[rt].sum = cnt[l];
return;
}
int mid = l + r >> 1;
build(rt << 1, l, mid);
build(rt << 1 | 1, mid + 1, r);
pushup(rt);
}
void modify(int rt, int l, int r)
{
if (l <= tree[rt].l&&r >= tree[rt].r)
{
tree[rt].sum = tree[rt].r - tree[rt].l + 1 - tree[rt].sum;
tree[rt].rev ^= 1;
return;
}
pushdown(rt);
int mid = tree[rt].l + tree[rt].r >> 1;
if (l <= mid)
modify(rt << 1, l, r);
if (r > mid)
modify(rt << 1 | 1, l, r);
pushup(rt);
}
int query(int rt, int ql,int qr)
{
if (ql <= tree[rt].l&&qr >= tree[rt].r)
{
return tree[rt].sum;
}
pushdown(rt);
int res = 0;
int mid = tree[rt].l + tree[rt].r >> 1;
if (ql <= mid)
res+=query(rt << 1, ql, qr);
if (qr > mid)
res+=query(rt << 1 | 1, ql, qr);
pushup(rt);
return res;
}
int ask1(int rt, int x)
{
if (tree[rt].r < x || tree[rt].sum == 0)return -1;
if (tree[rt].l == tree[rt].r)return tree[rt].l;
else
{
pushdown(rt);
int t = ask1(rt << 1, x);
if (~t)
return t;
return ask1(rt << 1 | 1, x);
}
}
int ask0(int rt, int x)
{
if (tree[rt].r < x || tree[rt].sum ==tree[rt].r-tree[rt].l+1)return -1;
if (tree[rt].l == tree[rt].r)return tree[rt].l;
else
{
pushdown(rt);
int t = ask0(rt << 1, x);
if (~t) {
return t;
} return ask0(rt << 1 | 1, x);
}
}
int ans(int rt)//找最左边1
{
if (tree[rt].l == tree[rt].r)return tree[rt].l;
else
{
pushdown(rt);
int mid = tree[rt].l + tree[rt].r>>1;
if (tree[rt << 1 | 1].sum)return ans(rt << 1 | 1);
else
return ans(rt << 1);
}
}
signed main()
{
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
cin >> a[i]; cnt[a[i]]++;
}
for (int i = 0; i < maxn - 1; i++)
{
cnt[i + 1] += cnt[i] / 2;
cnt[i] %= 2;
}
build(1, 1, maxn - 1);
while (m--)
{
int x, y;
cin >> x >> y;
int t = query(1, a[x],a[x]);
if (t == 1)
{
modify(1, a[x], a[x]);
}
else
{
int l = a[x], r = ask1(1, a[x]);//找a[x]右边最靠近的1
modify(1, l, r);
}
a[x] = y;
t = query(1, a[x], a[x]);
if (t == 0)
{
modify(1, a[x], a[x]);
}
else
{
int l = a[x], r = ask0(1, a[x]);
modify(1, l, r);
}
cout << ans(1) << endl;
}
}