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\)

  1. 直接选最小的

\(b\)

  1. \(b\)

  2. \(a\), 把之前一个 \(a\) 改成 \(b\)

\(c\)

  1. \(c\)

  2. \(b\),改之前的一个 \(b\)\(c\)

  3. \(a\),改之前的一个 \(a\)\(c\)

  4. \(a\),改之前的一个 \(a\)\(b\) ,一个 \(b\)\(c\)

  5. \(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;
}

posted @ 2022-11-24 19:12  Chen_jr  阅读(8)  评论(0编辑  收藏  举报