A.环鸽的CHONG

    对于a[i] = x而言,最大的区间[l, r]只包含一个x,那么这个区间[l, r]是一个好区间,依次递归判断是否[l, i - 1]和[i + 1, r]这两个区间同时满足是好区间,预处理每一个数前一次出现的位置和后一次出现的位置,然后递归处理即可。

/**/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <stack>
#include <queue>
#include <unordered_map>

typedef long long LL;
using namespace std;

int n, a[200005], l[200005], r[200005];
unordered_map<int, int> mp;

int dfs(int L, int R){
	if(R - L <= 0) return true;
	int x = L, y = R, mid = -1;
	while(x <= y){
		if(l[x] < L && R < r[x]) {mid = x; break;}
		if(l[y] < L && R < r[y]) {mid = y; break;}
		x++, y--;
	}
	if(mid == -1) return false;
	return dfs(L, mid - 1) && dfs(mid + 1, R);
}

int main()
{
	//freopen("in.txt", "r", stdin);
	//freopen("out.txt", "w", stdout);

	scanf("%d", &n);
	for (int i = 1; i <= n; i++){
		scanf("%d", &a[i]);
	}
	for (int i = 1; i <= n; i++){
		if(!mp[a[i]]) l[i] = 0;
		else l[i] = mp[a[i]];
		mp[a[i]] = i;
	}
	mp.clear();
	for (int i = n; i >= 1; i--){
		if(!mp[a[i]]) r[i] = n + 1;
		else r[i] = mp[a[i]];
		mp[a[i]] = i;
	}
	if(dfs(1, n)) printf("chong\n");
	else printf("fuchong\n");

	return 0;
}
/**/

B. 环鸽的数列列

对于每一个区间添加操作,都是从F1开始添加。

构造矩阵:

所以有,特别的有,那么我们维护区间[L, R]的时候,如果知道区间左端点L的矩阵为A,那么区间总和可以表示为,所以,我们可以先预处理出的前缀和用来维护区间左端点的值。对于区间左端点L的矩阵初始化为,然后用线段树维护区间和即可
/**/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <stack>
#include <queue>

typedef long long LL;
using namespace std;

const long long mod = 998244353;

int n, m, a[100005];

struct M
{
	LL m[2][2];
	friend M operator +(M a, M b){
		M c;
		memset(c.m, 0, sizeof(c.m));
		for (int i = 0; i < 2; i++){
			for (int j = 0; j < 2; j++){
				c.m[i][j] = (a.m[i][j] + b.m[i][j]) % mod;
			}
		}
		return c;
	}
	friend M operator -(M a, M b){
		M c;
		memset(c.m, 0, sizeof(c.m));
		for (int i = 0; i < 2; i++){
			for (int j = 0; j < 2; j++){
				c.m[i][j] = (a.m[i][j] - b.m[i][j] + mod) % mod;
			}
		}
		return c;
	}
	friend M operator *(M a, M b){
		M c;
		memset(c.m, 0, sizeof(c.m));
		for (int i = 0; i < 2; i++){
			for (int j = 0; j < 2; j++){
				for (int k = 0; k < 2; k++){
					c.m[i][j] = (c.m[i][j] + a.m[i][k] * b.m[k][j] % mod) % mod;
				}
			}
		}
		return c;
	}
}tr[100005 << 2], lzy[100005 << 2], p[100005], sum[100005];

void up(int rt){
	tr[rt] = tr[rt << 1] + tr[rt << 1 | 1];
}

void down(int rt, int l, int r){
	int mid = (l + r) >> 1;
	lzy[rt << 1] = lzy[rt << 1] + lzy[rt];
	lzy[rt << 1 | 1] = lzy[rt << 1 | 1] + (lzy[rt] * p[mid + 2 - l]);
	tr[rt << 1] = tr[rt << 1] + (sum[mid - l + 1] * lzy[rt]);
	tr[rt << 1 | 1] = tr[rt << 1 | 1] + ((sum[r - l + 1] - sum[mid - l + 1]) * lzy[rt]);
	memset(lzy[rt].m, 0, sizeof(lzy[rt].m));
}

void build(int rt, int l, int r){
	lzy[rt].m[0][0] = lzy[rt].m[0][1] = lzy[rt].m[1][0] = lzy[rt].m[1][1] = 0;
	tr[rt] = lzy[rt];
	if(l == r){
		tr[rt].m[0][0] = a[l];
		return ;
	}
	int mid = (l + r) >> 1;
	build(rt << 1, l, mid);
	build(rt << 1 | 1, mid + 1, r);
	up(rt);
}

void update(int rt, int l, int r, int L, int R){
	if(L <= l && r <= R){
		lzy[rt] = lzy[rt] + p[l - L + 1];
		tr[rt] = tr[rt] + (sum[r - L + 1] - sum[l - L]);
		return ;
	}
	down(rt, l, r);
	int mid = (l + r) >> 1;
	if(mid >= L) update(rt << 1, l, mid, L, R);
	if(mid < R) update(rt << 1 | 1, mid + 1, r, L, R);
	up(rt);
}

LL query(int rt, int l, int r, int L, int R){
	if(L <= l && r <= R) return tr[rt].m[0][0];
	down(rt, l, r);
	int mid = (l + r) >> 1;
	LL ans = 0;
	if(mid >= L) ans = (ans + query(rt << 1, l, mid, L, R)) % mod;
	if(mid < R) ans = (ans + query(rt << 1 | 1, mid + 1, r, L, R)) % mod;
	return (ans % mod + mod) % mod;
}

int main()
{
	//freopen("in.txt", "r", stdin);
	//freopen("out.txt", "w", stdout);

	p[1].m[0][0] = p[1].m[1][1] = 1;
	p[1].m[0][1] = p[1].m[1][0] = 0;
	sum[1] = p[1];
	M b;
	b.m[0][0] = 3, b.m[0][1] = 2, b.m[1][0] = 1, b.m[1][1] = 0;
	for (int i = 2; i <= 100000; i++) p[i] = p[i - 1] * b, sum[i] = sum[i - 1] + p[i];
	scanf("%d %d", &n, &m);
	for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
	build(1, 1, n);
	for (int i = 1, op, l, r; i <= m; i++){
		scanf("%d %d %d", &op, &l, &r);
		if(l > r) swap(l, r);
		if(op == 1){
			update(1, 1, n, l, r);
		}else{
			printf("%lld\n", query(1, 1, n, l, r));
		}
	}

	return 0;
}
/*
4 10
1 2 3 4
1 1 4
2 4 4
2 3 3
1 2 4
2 1 1
2 2 2
2 3 3
2 4 4
2 3 4
*/

C.环鸽不会X点

    1. 对于2*k次操作最少造成(1 + 2) * k点伤害

    2. 判断n和k的奇偶性不同(偶*偶为偶,奇*奇为奇)

/**/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <stack>
#include <queue>

typedef long long LL;
using namespace std;

int t, n, k;

int main()
{
	//freopen("in.txt", "r", stdin);
	//freopen("out.txt", "w", stdout);

	scanf("%d", &t);
	while(t--){
		scanf("%d %d", &n, &k);
		if(n < 3LL * k) printf("No\n");
		else{
			if(n % 2 != k % 2) printf("No\n");
			else printf("Yes\n");
		}
	}

	return 0;
}
/**/

D. 小C的棋王之路

    线段树区间维护乘,加,赋值模板题

/**/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <stack>
#include <queue>
 
typedef long long LL;
using namespace std;
 
const int mx = 200000;
 
int n, m, a[200005];
LL mod, tr[200005 << 2], lzy_add[200005 << 2], lzy_mu[200005 << 2];
 
void up(int rt){
    tr[rt] = (tr[rt << 1] + tr[rt << 1 | 1]) % mod;
}
 
void build(int rt, int l, int r){
    lzy_mu[rt] = 1;
    if(l == r){
        tr[rt] = a[l];
        return ;
    }
    int mid = (l + r) >> 1;
    build(rt << 1, l, mid);
    build(rt << 1 | 1, mid + 1, r);
    up(rt);
}
 
void update(int rt, int l, int r, int L, int R, int k, int x){
    // printf("%d %d\n", l, r);
    if(L == l && r == R){
        tr[rt] = (tr[rt] * x % mod + (LL)k * (r - l + 1) % mod) % mod;
        lzy_mu[rt] = lzy_mu[rt] * x % mod, lzy_add[rt] = (lzy_add[rt] * x % mod + k) % mod;
        return ;
    }
    int mid = (l + r) >> 1;
    if(lzy_mu[rt] != 1 || lzy_add[rt]){
        update(rt << 1, l, mid, l, mid, lzy_add[rt], lzy_mu[rt]);
        update(rt << 1 | 1, mid + 1, r, mid + 1, r, lzy_add[rt], lzy_mu[rt]);
        lzy_add[rt] = 0, lzy_mu[rt] = 1;
    }
    if(mid >= R) update(rt << 1, l, mid, L, R, k, x);
    else if(mid < L) update(rt << 1 | 1, mid + 1, r, L, R, k, x);
    else update(rt << 1, l, mid, L, mid, k, x), update(rt << 1 | 1, mid + 1, r, mid + 1, R, k, x);
    up(rt);
}
 
LL query(int rt, int l, int r, int L, int R){
    if(L == l && r == R) return tr[rt];
    int mid = (l + r) >> 1;
    if(lzy_mu[rt] != 1 || lzy_add[rt]){
        update(rt << 1, l, mid, l, mid, lzy_add[rt], lzy_mu[rt]);
        update(rt << 1 | 1, mid + 1, r, mid + 1, r, lzy_add[rt], lzy_mu[rt]);
        lzy_add[rt] = 0, lzy_mu[rt] = 1;
    }
    if(mid >= R) return query(rt << 1, l, mid, L, R);
    else if(mid < L) return query(rt << 1 | 1, mid + 1, r, L, R);
    else return (query(rt << 1, l, mid, L, mid) + query(rt << 1 | 1, mid + 1, r, mid + 1, R)) % mod;
}
 
int main()
{
    //freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
 
    scanf("%d %d %lld", &n, &m, &mod);
    for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
    build(1, 1, mx);
    for (int i = 1, op, l, r, k, x; i <= m; i++){
        scanf("%d", &op);
        if(op == 1){
            scanf("%d %d %d", &l, &r, &k);
            update(1, 1, mx, l, r, k, 1);
        }else if(op == 2){
            scanf("%d %d %d", &l, &r, &k);
            update(1, 1, mx, l, r, 0, k);
        }else if(op == 3){
            scanf("%d %d %d", &l, &r, &k);
            update(1, 1, mx, l, r, k, 0);
        }else if(op == 4){
            scanf("%d", &x);
            n++;
            update(1, 1, mx, n, n, x, 0);
        }else{
            scanf("%d %d", &l, &r);
            if(l > r) swap(l, r);
            printf("%lld\n", query(1, 1, mx, l, r));
        }
    }
 
    return 0;
}
/**/


或者直接套珂朵莉树板子
/**/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <stack>
#include <queue>
 
typedef long long LL;
using namespace std;
 
int n, m;
LL mod;
 
struct node
{
    int l, r;
    mutable LL val;
    node(int l, int r = -1, LL val = 0) : l(l), r(r), val(val) {}
    bool operator <(const node &rhs)const{
        return l < rhs.l;
    }
};
 
set<node> s;
 
auto split(int x){
    auto it = s.lower_bound(x);
    if(it != s.end() && it->l == x) return it;
    --it;
    int l = it->l, r = it->r;
    LL val = it->val;
    s.erase(it);
    s.insert(node(l, x - 1, val));
    return s.insert(node(x, r, val)).first;
}
 
void add(int l, int r, int x){
    auto itr = split(r + 1), itl = split(l);
    for (; itl != itr; itl++) itl->val = (itl->val + x) % mod;
}
 
void mul(int l, int r, int x){
    auto itr = split(r + 1), itl = split(l);
    for (; itl != itr; itl++) itl->val = itl->val * x % mod;
}
 
void assign(int l, int r, int x){
    auto itr = split(r + 1), itl = split(l);
    s.erase(itl, itr);
    s.insert(node(l, r, x));
}
 
LL query(int l, int r){
    LL ans = 0;
    auto itr = split(r + 1), itl = split(l);
    for (; itl != itr; itl++) ans = (ans + itl->val * (itl->r - itl->l + 1) % mod) % mod;
    return ans;
}
 
int main()
{
    //freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
 
    scanf("%d %d %lld", &n, &m, &mod);
    for (int i = 1, x; i <= n; i++){
        scanf("%d", &x);
        s.insert(node(i, i, x));
    }
    ++n;
    s.insert(node(n, n, 0));
    for (int i = 1, op, l, r, k, x; i <= m; i++){
        scanf("%d", &op);
        if(op <= 3){
            scanf("%d %d %d", &l, &r, &k);
            if(op == 1) add(l, r, k);
            else if(op == 2) mul(l, r, k);
            else assign(l, r, k);
        }else if(op == 4){
            scanf("%d", &x);
            auto it = s.lower_bound(node(n));
            s.erase(it);
            s.insert(node(n, n, x));
            ++n;
            s.insert(node(n, n, 0));
        }else{
            scanf("%d %d", &l, &r);
            printf("%lld\n", query(l, r));
        }
    }
 
    return 0;
}
/**/

E. 兰德索尔的瞭望塔

将一个点连接原点向量称为l[i],连接军营向量称为r[i]

首先将l[i]根据斜率从小到大排序

然后问题即转化为求r[i]的最长严格上升子序列(这里所谓的上升具体看下图)

对于当前线i,用dp[i] = max{dp[j]} + 1, (1 <= j< i且满足j线在i线的逆时针方向)
判断一条线在另一条线的方向时,用几何里的叉积即可(表示j线在i线逆时针方向, = 0表示同线,< 0 表示顺时针方向)
最后注意l[i]斜率相同情况即可
/**/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <stack>
#include <queue>

typedef long long LL;
using namespace std;

int n, x, ans, dp[100005];

struct node
{
	LL x, y;
	friend LL operator * (node a, node b){
		return a.x * b.y - a.y * b.x;
	}
	friend node operator - (node a, node b){
		return node{a.x - b.x, a.y - b.y};
	}
	bool operator <(const node &rhs)const{
		return x * rhs.y - y * rhs.x > 0LL;
	}
}b[100005], a[100005];

int check(node a, node b){
	return a * b > 0LL;
}

int solve(node a){
	int l = 1, r = ans, res = 0;
	while(l <= r){
		int mid = (l + r) >> 1;
		if(check(a - node{x, 0}, b[mid])) res = mid, l = mid + 1;
		else r = mid - 1;
	}
	return res;
}

int main()
{
	//freopen("in.txt", "r", stdin);
	//freopen("out.txt", "w", stdout);

	while(scanf("%d %d", &n, &x) == 2){
		for (int i = 1; i <= n; i++) scanf("%lld %lld", &a[i].x, &a[i].y);
		sort(a + 1, a + 1 + n);
		ans = 0;
		for (int i = 1, j; i <= n; i = j){
			j = i + 1;
			while(a[j] * a[i] == 0 && j <= n) j++;
			int p = i;
			for (int k = i + 1; k < j; k++) if(check(a[p] - node{x, 0}, a[k] - node{x, 0})) p = k;
			b[dp[p] = solve(a[p]) + 1] = a[p] - node{x, 0};
			ans = max(ans, dp[p]);
		}
		printf("%d\n", ans);
	}
	
	

	return 0;
}
/**/