2022NOIP A层联测34
A. bs 串
发现找 \(b - s - b - -------- b\) 或者 \(s - b - s ------- s\)
于是二分+并查集维护
code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const int maxn = 500005;
int n, m, q, col[maxn];
int cnt, tot;
struct edge {
int u, v, tim;
} com[maxn], e[maxn];
struct DSU {
int f[maxn], siz[maxn];
vector<int> del, tim;
void init() {
for (int i = 1; i <= n; ++i) f[i] = i, siz[i] = 1;
}
int fa(int x) { return f[x] == x ? x : fa(f[x]); }
void merge(int x, int y, int now) {
x = fa(x);
y = fa(y);
if (x == y)
return;
if (siz[x] < siz[y])
swap(x, y);
del.push_back(y);
tim.push_back(now);
siz[x] += siz[y];
f[y] = x;
}
void Del(int Tim) {
while (tim.size()) {
if (tim.back() <= Tim)
return;
int y = del.back(), x = f[y];
del.pop_back();
tim.pop_back();
siz[x] -= siz[y];
f[y] = y;
}
}
} S;
int mid, pe;
bool check() {
while (pe < tot && e[pe + 1].tim <= mid) {
++pe;
S.merge(e[pe].u, e[pe].v, e[pe].tim);
}
S.Del(mid);
while (pe && e[pe].tim > mid) --pe;
for (int i = 1; i <= cnt && com[i].tim <= mid; ++i) {
if (S.fa(com[i].u) == S.fa(com[i].v))
return true;
}
return false;
}
char s[maxn];
int main() {
freopen("bssb.in", "r", stdin);
freopen("bssb.out", "w", stdout);
scanf("%d%d%d", &n, &m, &q);
scanf("%s", s + 1);
for (int i = 1; i <= n; ++i) col[i] = s[i] == 's';
S.init();
for (int i = 1; i <= m; ++i) {
int u, v;
scanf("%d%d", &u, &v);
if (col[u] == col[v]) {
com[++cnt] = { u, v, 0 };
} else
S.merge(u, v, 0);
}
for (int i = 1; i <= q; ++i) {
int u, v;
scanf("%d%d", &u, &v);
if (col[u] == col[v]) {
com[++cnt] = { u, v, i };
} else
e[++tot] = { u, v, i };
}
int l = 1, r = q, ans = q + 1;
while (l <= r) {
mid = (l + r) >> 1;
if (check())
r = mid - 1, ans = mid;
else
l = mid + 1;
}
for (int i = 1; i < ans; ++i) printf("No\n");
for (int i = ans; i <= q; ++i) printf("Yes\n");
return 0;
}
B. 英语作文
考场推了一堆奇怪的东西
最开始想维护句子,但是发现位置无法很好维护
根据数据范围猜测为线性做法,于是考虑顺序转移
然后把想到的情况都写下来
就有了 主, 主谓, 句, 句谓, 句谓主 。。。。。。。。
然后经过画图,发现最终结尾元素相同的完全一致
于是只用记录以主,谓,宾三者结尾的方案数
答案是宾语结尾的
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const int maxn = 500005;
int n, m, q, col[maxn];
int cnt, tot;
struct edge{int u, v, tim;}com[maxn], e[maxn];
struct DSU{
int f[maxn], siz[maxn];
vector<int>del, tim;
void init(){for(int i = 1; i <= n; ++i)f[i] = i, siz[i] = 1;}
int fa(int x){return f[x] == x ? x : fa(f[x]);}
void merge(int x, int y, int now){
x = fa(x); y = fa(y);
if(x == y)return;
if(siz[x] < siz[y])swap(x, y);
del.push_back(y); tim.push_back(now);
siz[x] += siz[y]; f[y] = x;
}
void Del(int Tim){
while(tim.size()){
if(tim.back() <= Tim)return;
int y = del.back(), x = f[y];
del.pop_back(); tim.pop_back();
siz[x] -= siz[y]; f[y] = y;
}
}
}S;
int mid, pe;
bool check(){
while(pe < tot && e[pe + 1].tim <= mid){
++pe; S.merge(e[pe].u, e[pe].v, e[pe].tim);
}
S.Del(mid);
while(pe && e[pe].tim > mid)--pe;
for(int i = 1; i <= cnt && com[i].tim <= mid; ++i){
if(S.fa(com[i].u) == S.fa(com[i].v))return true;
}
return false;
}
char s[maxn];
int main(){
freopen("bssb.in","r",stdin);
freopen("bssb.out","w",stdout);
scanf("%d%d%d",&n,&m,&q);
scanf("%s",s + 1);
for(int i = 1; i <= n; ++i)col[i] = s[i] == 's';
S.init();
for(int i = 1; i <= m; ++i){
int u, v; scanf("%d%d",&u,&v);
if(col[u] == col[v]){ com[++cnt] = {u, v, 0};}
else S.merge(u, v, 0);
}
for(int i = 1; i <= q; ++i){
int u, v; scanf("%d%d",&u,&v);
if(col[u] == col[v]){com[++cnt] = {u, v, i};}
else e[++tot] = {u, v, i};
}
int l = 1, r = q, ans = q + 1;
while(l <= r){
mid = (l + r) >> 1;
if(check())r = mid - 1, ans = mid;
else l = mid + 1;
}
for(int i = 1; i < ans; ++i)printf("No\n");
for(int i = ans; i <= q; ++i)printf("Yes\n");
return 0;
}
C. 计算器
发现一段操作可以看成先右移 \(a\), 再左移 \(b\) ,再加上 \(c\)
那么对于 \(lowbit\) 相同的数,他们的变化是相同的
于是可以拿线段树维护这个东西
合并两个三元组 \((a, b, c) (d, e, f)\)
考虑到
\(\huge \frac{\frac{x}{2^a}2^b}{2^d}2^f\)
中 \(b, d\) 的大小关系,于是有两种情况
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
int read(){
int x = 0; char c = getchar();
while(!isdigit(c))c = getchar();
do{x = x * 10 + (c ^ 48); c = getchar();}while(isdigit(c));
return x;
}
const int maxn = 200005;
int lim;
int n, m, q, cal[maxn];
char s[maxn];
struct note{
int a, b, c;
note(){a = b = c = 0;}
note(int _a, int _b, int _c){a = _a, b = _b, c = _c;}
int calc(int x){return x >> a << b | c;}
friend note operator + (const note &x, const note &y){
if(x.b < y.a)return {x.a + y.a - x.b, y.b, y.c + (x.c >> y.a << y.b)};
else return {x.a , x.b - y.a + y.b , y.c + (x.c >> y.a << y.b)};
}
};
void build(note a[], int op){
switch(op){
case 1: a[0] = {0, 0, 0}; for(int i = 1; i < m; ++i)a[i] = {1, 0, 0}; break;
case 2: for(int i = 0; i < m - 1; ++i)a[i] = {0, 1, 0}; a[m - 1] = {0, 0, 0}; break;
case 3: for(int i = 0; i < m - 1; ++i)a[i] = {0, 1, 1}; a[m - 1] = {0, 0, 0}; break;
case 4: for(int i = 0; i < m; ++i)a[i] = {i, 0, 0}; break;
case 5: for(int i = 0; i < m; ++i)a[i] = {0, m - i - 1, 0}; break;
case 6: for(int i = 0; i < m; ++i)a[i] = {0, m - i - 1, (1 << (m - i - 1)) - 1}; break;
}
}
struct seg{
struct node{
note a[33];
}t[maxn << 2 | 1];
void push_up(int x){
for(int i = 0; i < m; ++i){
note p = t[x << 1].a[i];
int len = i - p.a + p.b;
t[x].a[i] = p + t[x << 1 | 1].a[len];
}
}
void built(int x, int l, int r){
if(l == r)return build(t[x].a, cal[l]);
int mid = (l + r) >> 1;
built(x << 1, l, mid);
built(x << 1 | 1, mid + 1, r);
push_up(x);
}
void modify(int x, int l, int r, int pos){
if(l == r)return build(t[x].a, cal[l]);
int mid = (l + r) >> 1;
if(pos <= mid)modify(x << 1, l, mid, pos);
else modify(x << 1 | 1, mid + 1, r, pos);
push_up(x);
}
note query(int x, int l, int r, int L, int R, int bit){
if(L <= l && r <= R)return t[x].a[bit];
int mid = (l + r) >> 1;
if(R <= mid)return query(x << 1, l, mid, L, R, bit);
if(L > mid)return query(x << 1 | 1, mid + 1, r, L, R, bit);
note ans = query(x << 1, l, mid, L, R, bit);
ans = ans + query(x << 1 | 1, mid + 1, r, L, R, bit - ans.a + ans.b);
return ans;
}
}t;
int main(){
freopen("calculate.in","r",stdin);
// freopen("calculate.out","w",stdout);
n = read(), m = read(), q = read();
scanf("%s",s + 1);
for(int i = 1; i <= n; ++i)cal[i] = s[i] - '0';
t.built(1, 1, n);
for(int i = 1; i <= q; ++i){
int opt = read();
if(opt & 1){
int l = read(), r = read(), x = read();
printf("%d\n", t.query(1, 1, n, l, r, __lg(x)).calc(x));
}else{
int pos = read(), p = read();
cal[pos] = p;
t.modify(1, 1, n, pos);
}
}
return 0;
}
D. 愤怒的小鸟
可反悔贪心
先取 \(min\) 转化为取恰好 \(p, q, r\) 个
然后考虑选取\(a, b, c\)
选 \(a\)
- 直接选最小的
选 \(b\)
-
选 \(b\)
-
选 \(a\), 把之前一个 \(a\) 改成 \(b\)
选 \(c\)
-
选 \(c\)
-
选 \(b\),改之前的一个 \(b\) 为 \(c\)
-
选 \(a\),改之前的一个 \(a\) 为 \(c\)
-
选 \(a\),改之前的一个 \(a\) 为 \(b\) ,一个 \(b\) 为 \(c\)
-
选 \(b\), 改之前一个 \(b\) 为 \(a\), 一个 \(a\) 为 \(c\)
八种情况,七个堆
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, int> pli;
int read(){
int x = 0; char c = getchar();
while(!isdigit(c))c = getchar();
do{x = x * 10 + (c ^ 48); c = getchar();}while(isdigit(c));
return x;
}
const int maxn = 200055;
int n, p, q, r;
int a[maxn], b[maxn], c[maxn];
int vis[maxn];
priority_queue<pli>qcb, qba, qca, qbc;
priority_queue<pli, vector<pli>, greater<pli>>qa, qb, qc;
void make_3star(int x){
vis[x] = 3;
qcb.push(pli(c[x] - b[x], x));
qca.push(pli(c[x] - a[x], x));
}
void make_2star(int x){
vis[x] = 2;
qba.push(pli(b[x] - a[x], x));
qbc.push(pli(b[x] - c[x], x));
}
void make_1star(int x){
vis[x] = 1;
}
ll get_1star(){
while(!qa.empty() && vis[qa.top().second])qa.pop();
return qa.empty() ? 1e18 : qa.top().first;
}
ll get_2star(){
while(!qb.empty() && vis[qb.top().second])qb.pop();
return qb.empty() ? 1e18 : qb.top().first;
}
ll get_3star(){
while(!qc.empty() && vis[qc.top().second])qc.pop();
return qc.empty() ? 1e18 : qc.top().first;
}
ll make3to2(){
while(!qcb.empty() && vis[qcb.top().second] != 3)qcb.pop();
return qcb.empty() ? -1e18 : qcb.top().first;
}
ll make3to1(){
while(!qca.empty() && vis[qca.top().second] != 3)qca.pop();
return qca.empty() ? -1e18 : qca.top().first;
}
ll make2to1(){
while(!qba.empty() && vis[qba.top().second] != 2)qba.pop();
return qba.empty() ? -1e18 : qba.top().first;
}
ll make2to3(){
while(!qbc.empty() && vis[qbc.top().second] != 2)qbc.pop();
return qbc.empty() ? -1e18 : qbc.top().first;
}
ll ans;
int main(){
freopen("angrybird.in","r",stdin);
freopen("angrybird.out","w",stdout);
n = read(), p = read(), q = read(), r = read();
for(int i = 1; i <= n; ++i)a[i] = read();
for(int i = 1; i <= n; ++i)b[i] = read();
for(int i = 1; i <= n; ++i)c[i] = read();
for(int i = 1; i <= n; ++i)b[i] = min(b[i], c[i]);
for(int i = 1; i <= n; ++i)a[i] = min(a[i], b[i]);
for(int i = 1; i <= n; ++i){qa.push(pli(a[i], i)); qb.push(pli(b[i], i)); qc.push(pli(c[i], i));}
p = p - max(q, r); q = q - r;
for(int i = 1; i <= r; ++i)make_3star(qc.top().second), ans += qc.top().first, qc.pop();
for(int i = 1; i <= q; ++i){
ll v1 = get_2star(), v2 = get_3star() - make3to2();
if(v1 < v2){
ans += v1;
make_2star(qb.top().second);
qb.pop();
}else{
ans += v2;
int x = qc.top().second, y = qcb.top().second;
qc.pop(); qcb.pop();
make_3star(x); make_2star(y);
}
}
for(int i = 1; i <= p; ++i){
ll v1 = get_1star(), v2 = get_2star() - make2to1(), v3 = get_3star() - make3to1(), v4 = get_3star() - make2to1() - make3to2(), v5 = get_2star() - make3to1() - make2to3();
if(v1 < v2 && v1 < v3 && v1 < v4 && v1 < v5){
ans += v1;
make_1star(qa.top().second);
qa.pop();
}else if(v2 < v3 && v2 < v4 && v2 < v5){
ans += v2;
int x = qb.top().second, y = qba.top().second;
qb.pop(); qba.pop();
make_2star(x); make_1star(y);
}else if(v3 < v4 && v3 < v5){
ans += v3;
int x = qc.top().second, y = qca.top().second;
qc.pop(); qca.pop();
make_3star(x); make_1star(y);
}else if(v4 < v5){
ans += v4;
int x1 = qc.top().second, x2 = qba.top().second, x3 = qcb.top().second;
qc.pop(); qba.pop(); qcb.pop();
make_3star(x1); make_2star(x3); make_1star(x2);
}else{
ans += v5;
int x1 = qb.top().second, x2 = qca.top().second, x3 = qbc.top().second;
qb.pop(); qca.pop(); qbc.pop();
make_3star(x3); make_2star(x1); make_1star(x2);
}
}
printf("%lld\n",ans);
return 0;
}