yuwj  

abc388

D

线段树板子改两行,支持单点查询,区间加就完了

没有思维难度,存板子没有码量

template <class Info>
struct SegmentTree {
	struct Node {
		int l, r;
		Info info;
		int tag;
	};

	std::vector<Node> tr;

	SegmentTree() {};
	SegmentTree(int n) {
		init(n);
	}

	SegmentTree(std::vector<Info> & info) {
		init(info);
	}

	void init(int n) {
		tr.assign(n << 2, {});
		build(0, n - 1);
	}

	void init(std::vector<Info> & info) {
		int n = info.size();
		tr.assign(n << 2, {});
		std::function<void(int, int, int)> build = [&](int l, int r, int u) -> void {
			tr[u] = {l, r, {},0};
			if (l == r) {
				tr[u].info = info[l];
				return;
			}

			int mid = l + r >> 1;
			build(l, mid, u << 1); build(mid + 1, r, u << 1 | 1);
			pushup(u);
		};

		build(0, n - 1, 1);
	}

	void pushup(int u) {
		tr[u].info = tr[u << 1].info + tr[u << 1 | 1].info;
	}

	void apply(int idx,int val){
		tr[idx].info.sum += (tr[idx].r-tr[idx].l+1)*val;
		tr[idx].tag += val;
	}
	
	void pushdown(int idx){
		if(tr[idx].tag==0)return;
		apply(idx*2,tr[idx].tag);
		apply(idx*2+1,tr[idx].tag);
		tr[idx].tag=0;
	}

	void build(int l, int r, int u = 1) {
		tr[u] = {l, r, {}, -1};
		if (l == r) {
			return;
		}

		int mid = l + r >> 1;
		build(l, mid, u << 1); build(mid + 1, r, u << 1 | 1);
		pushup(u);
	}

	void modify(int p, const Info & info, bool set = false) {
		int u = 1;
		while (tr[u].l != tr[u].r) {
			int mid = tr[u].l + tr[u].r >> 1;
			if (p <= mid) {
				u = u << 1;
			} else {
				u = u << 1 | 1;
			}
		}

		if (set) {
			tr[u].info = info;
		} else {
			tr[u].info = tr[u].info + info;
		}

		u >>= 1;
		while (u) {
			pushup(u);
			u >>= 1;
		}
	}

	//修改和查询要push_down
	void change(int l,int r,int idx, int val){
		if(l<=tr[idx].l && tr[idx].r <= r) {apply(idx,val);return;}
		pushdown(idx);
		int mid = (tr[idx].l + tr[idx].r) >> 1;
		if(l<=mid) change(l,r,idx*2,val);
		if(mid<r) change(l,r,idx*2+1,val);
		pushup(idx);
	}

	Info query(int l, int r, int u = 1) {
		if (l <= tr[u].l && tr[u].r <= r) {
			return tr[u].info;
		}
		pushdown(u);
		int mid = tr[u].l + tr[u].r >> 1;
		if (r <= mid) {
			return query(l, r, u << 1);
		} else if (l > mid) {
			return query(l, r, u << 1 | 1);
		}

		return query(l, r, u << 1) + query(l, r, u << 1 | 1);
	}
};

struct Info{
	ll sum;
	Info():sum(0){}
	Info(int x):sum(x){}
};

Info operator+(const Info l,const Info r){
	Info res;
	res.sum=l.sum+r.sum;
	return res;
}

void solve(){
	cin >> n;
	vector<int> num(n+1), ans(n+1);
	vector<Info> info(n+1);
	For(i,1,n) cin >> num[i], info[i] = Info(0);
	SegmentTree<Info> segs(info);
	For(i,1,n){
		x = num[i] + segs.query(i,i).sum;
		int len = min(n-i,x);
		segs.change(i+1,i+len,1,1);
		ans[i] = x - len;
	}

	For(i,1,n) cout << ans[i] << " \n"[i == n];
}

E

题意:

一个非递减数组,一对数字定义为 $(a,b)$,$2a \le b$,问最多可以出多少对?

思路:

显然二分,对于每一个mid,显然让最小的 mid 个,和最大的 mid 个配对即可,如果无法配对成功就不行

void solve(){
	cin >> n;
	vector<int> num(n+1);
	For(i,1,n) cin >> num[i];

	// 能不能拿到 mid 对
	auto check=[&](int mid) -> bool{
		for(int i=1;i<=mid;++i){
			int j = n - mid + i;
			if(num[i]*2 > num[j]) return 0;
		}
		return 1;
	};

	int l = 0, r = n/2,mid,ans;
	while(l<=r){
		mid = (r+l)>>1;
		if(check(mid)) l = mid + 1, ans = mid;
		else r = mid-1;
	}

	cout << ans << '\n';
}

F

$dp_i$ 表示第 $i$ 个点能不能到,由于 $B \le 20$,所以可以直接考虑从前 $20$ 个位置的向量暴力转移,转移方程就是

$dp_i = \or_{j=a}^{b} dp_{i-j}$ ,使用矩阵快速幂优化即可,

#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
#define For(i,a,b) for(int i=(a);i<=(b);++i)
#define all(v) v.begin(), v.end()
#define pb push_back
#define inf32 INT_MAX
#define inf64 LLONG_MAX
#define int ll
typedef long long ll;
typedef unsigned long long ull;
typedef std::pair<int,int> pii;
mt19937_64 rng(time(0));
ll qmi(ll a, ll k, int m){ll res=1;while(k){if(k&1)res=res*a%m;a=a*a%m;k>>=1;}return res;}
const int Maxn = 20 + 5, Maxm = 2e4 + 5, N = 20, Mod = 998244353;
int n,m,k,x,y,z,q,A,B, m1, m2, l, r,u,v;
string s,Map[Maxn];
vector<int> G[Maxn];

struct Matrix{
	bool a[Maxn][Maxn];
	Matrix(){memset(a,0,sizeof a);}
	
	Matrix operator*(const Matrix &t) const{
		Matrix res;
		For(k,1,N) For(i,1,N) For(j,1,N){
			res.a[i][j] |= (a[i][k] & t.a[k][j]); // 矩阵乘法,i行j列 * i 行 j 列 的矩阵
		}
		return res;
	}
}MG,MB, MG_pw[41], MB_pw[41];

bool f[Maxn], new_f[Maxn];
ll L[Maxm], R[Maxm];

void apply(int type, int n){
	For(i,0,40){ // 矩阵快速幂,奇数次乘法得到向量优化乘 B^2
		if((n>>i) &1){
			memset(new_f, 0, sizeof new_f);
			For(x,1,N) For(y,1,N){ // A[x][y] * f[y] = new_f[y]
				new_f[x] |= (type ? MG_pw : MB_pw)[i].a[x][y] & f[y];
			}
			For(x,1,N) f[x] = new_f[x];
		}
	}
}

void solve(){
	cin >> n >> m >> A >> B;
	For(i,1,m) {cin >> L[i] >> R[i];}

	For(i,A,B) MG.a[1][i] = 1;
	For(i,2,N) MG.a[i][i-1] = 1;
	For(i,2,N) MB.a[i][i-1] = 1;

	MG_pw[0] = MG, MB_pw[0] = MB;
	For(i,1,40){
		MG_pw[i] = MG_pw[i-1] * MG_pw[i-1];
		MB_pw[i] = MB_pw[i-1] * MB_pw[i-1];
	}

	f[1] = 1; int now = 1;
	For(i,1,m){
		// [now+1, l[i]-1] GOOD
		// [l[i], r[i]] Bad
		apply(1ll,L[i]-1-now); // 好矩阵
		apply(0ll,R[i]-L[i]+1); // 坏矩阵
		now = R[i];
	}

	apply(1ll,n - now);
	puts(f[1]?"Yes":"No");
}

signed main() {
    ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
	int t = 1;
	// cin >> t;
	while (t -- ) {
		solve();
	}
	return 0;
}
/**
 *  心中无女人
 *  比赛自然神
 *  模板第一页
 *  忘掉心上人
**/
posted on 2025-09-25 22:29  xiaowang524  阅读(7)  评论(0)    收藏  举报