无限欢愉 深入推进 我沦陷在那片故地 我渴饮着 你的呼吸 却得不到 你的心

test33

要死了喵。好想锤爆 * * * * * * 喵。

要死了喵。好想锤爆 * * * * * * 喵。

要死了喵。好想锤爆 * * * * * * 喵。

5-A 骑行 (cycle.cpp)

先对 \(a\) 排序,考虑怎么贪心 \(b\),有一个一定贡献的点,对它贪心,发现答案相当于正反排序弄在一起喵。

#include<bits/stdc++.h>
#define int long long
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)

using namespace std;

const int N=1000005;

int Type, n, a[N], b[N], Ans;

signed main() {
//	freopen("1.txt","r",stdin);
	freopen("cycle.in","r",stdin);
	freopen("cycle.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> Type >> n;
	up(i,1,n) cin >> a[i];
	up(i,1,n) cin >> b[i];
	sort(a+1,a+1+n);
	sort(b+1,b+1+n);
	if(Type==2) up(i,1,n/2) swap(b[i],b[n-i+1]);
	up(i,1,n) Ans+=max(a[i],b[i]);
	cout << Ans << '\n'; 
	return 0;
}

5-B 游戏 (game.cpp)

先转转 \(a_i\in[0,m)\),然后 \(x\) 肯定是某个 \(a_i\) 你可以考虑数轴上两边的权如果相等那无所谓、如果不等一定会往一边走喵。

然后你枚举 \(x=a_1,\dots,a_n\),考虑 \(a_i-x\in(-m,m)\),你划分开来范围,是单调的,run 四个指针就好了喵。

#include<bits/stdc++.h>
#define int long long
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)

using namespace std;

const int N=200005, inf=1e18;

int T, n, m, v[N], A, B, C, D, Ans, s[N];

void mian() {
	cin >> n >> m, A=B=C=D=0, Ans=inf;
	up(i,1,n) cin >> v[i], v[i]=(v[i]%m+m)%m;
	sort(v+1,v+1+n);
	up(i,1,n) s[i]=s[i-1]+v[i];
	up(u,1,n) {
		int x=v[u];
		while(A<n&&v[A+1]-x<-m/2) ++A;
		while(B<n&&v[B+1]-x<=0) ++B;
		while(C<n&&v[C+1]-x<=m/2) ++C;
		while(D<n&&v[D+1]-x<m) ++D;
		int val=0;
		if(0<A) val+=(A-0)*(m-x)+(s[A]-s[0]);
		if(A<B) val+=(B-A)*x-(s[B]-s[A]);
		if(B<C) val+=(s[C]-s[B])-(C-B)*x;
		if(C<D) val+=(D-C)*(m+x)-(s[D]-s[C]);
		Ans=min(Ans,val); 
	}
	cout << Ans << '\n';
}

signed main() {
//	freopen("1.txt","r",stdin);
	freopen("game.in","r",stdin);
	freopen("game.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> T;
	while(T--) mian();
	return 0;
}

5-C 序列 (seq.cpp)

按顺序插♂入,显然只关心三元组 \((i,j)\),然后要记一个对应的 \(\max\{w\}\),你肯定不能存下所有的状态喵,所以往支配点对那边去想喵,显然对于一个 \(j\) 只关心 \(i\) 不相等的最大/次大 \(w\),然后你好像不太关心很多个 \(j\) 来着,因为你的限制只有颜色 diff,你考虑排除一个相等的 \(j\),然后你还要额外两种 \(j\),所以三种 \(j\) 是极限了喵。

#include<bits/stdc++.h>
#define int long long
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)
#define pb push_back

using namespace std;

const int N=200005;

int T, n, a[N], Ans;

struct node {
	int l, r, v;
	bool operator<(const node &rhs) const { return v<rhs.v; } 
};
vector<node> sav;

void insert(node now) {
	int cnt=0;
	for(node &u:sav) {
		if(u.r==now.r) ++cnt;
		if(u.l==now.l&&u.r==now.r) {
			u.v=max(u.v,now.v);
			return;
		}
	}
	if(cnt==2) {
		for(node &u:sav) {
			if(u.r!=now.r) continue;
			if(now.v>u.v) swap(now,u);
		}
	}
	else {
		if(sav.size()==6) {
			for(node &u:sav) {
				if(now.v>u.v) swap(now,u);
			}
		}
		else {
			sav.pb(now);
		}
	}
}

void mian() {
	cin >> n, Ans=0;
	up(i,1,n) cin >> a[i];
	sav.clear(), sav.pb((node){0,0,0});
	up(o,1,n) {
		int i=a[o];
		node L=(node){0,i,1};
		node R=(node){0,i,1};
		for(node u:sav) {
			if(u.l==i||u.r==i) continue;
			if(u.v+1>L.v) {
				if(u.r!=L.l) R=L;
				L=(node){u.r,i,u.v+1};
			}
			else if(u.r!=L.l) {
				if(u.v+1>R.v) R=(node){u.r,i,u.v+1};
			}
		}
		Ans=max(Ans,L.v);
		insert(L), insert(R);
	}
	cout << Ans << '\n';
}

signed main() {
//	freopen("1.txt","r",stdin);
	freopen("seq.in","r",stdin);
	freopen("seq.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> T;
	while(T--) mian();
	return 0;
}

5-D 城墙 (wall.cpp)

亲自尝试过直接上线段树计算 \(\sum_{h_u=a_u/b_u}\sum_{i=1}^n\min\{\max(h_{1\to i}),\max(h_{i\to n})\}\),被严格偏序、幂次讨论和常数创飞了。

首先你可以把墙高消掉,算水位线和是多少,墙高和显然是 \(2^{n-1}\sum(a_i+b_i)\)

考虑计算 \(\sum_{H}\sum_{h_u=a_u/b_u}\sum_{i=1}^n[\max(h_{1\to i}\geq H,\max(h_{i\to n})\geq H)]\) 也就是差分成 01 序列,\(1\) 是大于等于的,设 \(cnt_i\) 表示 \(a_i/b_i\)\(\geq H\) 的数量,\(counter_i\) 表示 \(cnt_u=i\) 的数量,题目变成了从大到小枚举 \(H\) 的间隔、修改 \(cnt\)\(counter\),快速查询 \(\sum_{h_u=[a_u\geq H]/[b_u\geq H]}\sum_{i=1}^n[\exists l\leq i\leq r,h_l=h_r=1]\),不妨看看 \(i\) 的贡献更具体可以拆成什么 qwq

  • \(h_u=1\),一定贡献,系数 \(2^{n-1}\),当然藏了一个 \(\times cnt_i\) 喵。

这个直接用 \(counter\) 就能快速算了,贡献 \(2^{n-1}(2counter_2+counter_1)\)

  • \(h_u=0\),要求存在 \(h_{l/r}=1\),设前/后 \(cnt_u=2/0\) 的数量为 \(x_l/x_r/z_l/z_r\),系数 \((2^{i-1}-[x_l=0]2^{z_l})(2^{n-i}-[x_r=0]2^{z_r})\),当然藏了一个 \(\times(2-cnt_i)\) 喵,我们考虑乘出来。
  1. \(\sum (2-cnt_i)2^{i-1}\times 2^{n-i}\)

改成 \(2^{n-1}(2counter_0+counter_1)\) 就行了喵。

  1. \(\sum(2-cnt_i)[x_l=0][x_r=0]2^{z_l+z_r}\)

首先 \(conter_2\neq 0\) 没有贡献,\(counter_2=0\) 的情况贡献 \(counter_0\times 2^{counter_0-1}\times 2+counter_1\times 2^{counter_1}=2^{counter_0}(counter_0+counter_1)\)

  1. \(-\sum 2^{i-1}[x_r=0]2^{z_r}\times (2-cnt_i)\)

\(2^{i-1}(2-cnt_i)\) 看作单点上的权值,\([x_r=0]\) 看作增加前缀的乘法贡献,\(2^{z_r}\) 对每一个 \(cnt_u=0\) 看作撤销前缀乘法贡献,可以先全都加上去然后用逆元撤销,线段树容易维护。

  1. \(-\sum 2^{n-i}[x_l=0]2^{zl}\times (2-cnt_i)\)

同第三类,多开一颗线段树即可。

#include<bits/stdc++.h>
#define int long long 
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)

using namespace std;

const int N=1000005, P=1e9+7, inv2=500000004;

int n, pw[N], a[N], b[N], ran[N], cnt[N], counter[3];
int Ans, sp[N], m;

inline int id(int i) { return i<=n?i:(i-n); }
inline int calc(int i) { return i<=n?a[i]:b[i-n]; }
inline void Mul(int &a,int b) { (a*=b)%=P; }
inline void Add(int &a,int b) { (a+=b)%=P; }

struct SGT {
	int Type, tr[N<<2], mul[N<<2];
	inline void tup(int p) {
		tr[p]=(tr[ls(p)]+tr[rs(p)])%P;
	}
	inline void tdn(int p) {
		Mul(mul[ls(p)],mul[p]), Mul(tr[ls(p)],mul[p]);
		Mul(mul[rs(p)],mul[p]), Mul(tr[rs(p)],mul[p]);
		mul[p]=1;
	}
	void build(int p=1,int s=1,int e=n) {
		mul[p]=1;
		if(s==e) { tr[p]=(2-cnt[s])*(Type?pw[n-s]:pw[s-1])%P; return; }
		int mid=(s+e)>>1;
		build(ls(p),s,mid), build(rs(p),mid+1,e);
		tup(p);
	}
	void modify(int l,int r,int v,int p=1,int s=1,int e=n) {
		if(l>r) return;
		if(l<=s&&e<=r) {
			Mul(mul[p],v), Mul(tr[p],v);
			return;
		}
		tdn(p);
		int mid=(s+e)>>1;
		if(l<=mid) modify(l,r,v,ls(p),s,mid);
		if(r>mid) modify(l,r,v,rs(p),mid+1,e);
		tup(p);
	}
	void point(int x,int p=1,int s=1,int e=n) {
		if(s==e) { tr[p]=mul[p]*(2-cnt[s])%P*(Type?pw[n-s]:pw[s-1])%P; return; }
		tdn(p);
		int mid=(s+e)>>1;
		if(x<=mid) point(x,ls(p),s,mid);
		if(x>mid) point(x,rs(p),mid+1,e);
		tup(p); 
	}
} L, R; 

signed main() {
//	freopen("1.txt","r",stdin);
	freopen("wall.in","r",stdin);
	freopen("wall.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> n, pw[0]=1;
	up(i,1,n) pw[i]=2*pw[i-1]%P;
	up(i,1,n) cin >> a[i], sp[++m]=a[i], ran[i]=i;
	up(i,1,n) cin >> b[i], sp[++m]=b[i], ran[i+n]=i+n;
	sort(sp+1,sp+1+m), m=unique(sp+1,sp+1+m)-sp-1;
	sort(ran+1,ran+1+2*n,[](int i,int j){return calc(i)>calc(j);});
	L.Type=0, L.build(), R.Type=1, R.build();
	up(i,1,n) L.modify(1,i-1,2), R.modify(i+1,n,2), ++counter[0];
	int j=1;
	dn(i,m,1) {
		while(j<=2*n&&calc(ran[j])>=sp[i]) {
			int u=id(ran[j++]);
			--counter[cnt[u]], ++cnt[u], ++counter[cnt[u]];
			if(cnt[u]==1) L.modify(1,u-1,inv2), R.modify(u+1,n,inv2);
			else L.modify(1,u-1,0), R.modify(u+1,n,0);
			L.point(u), R.point(u);
		}
		int val=0;
		Add(val,(2*counter[0]+counter[1])*pw[n-1]%P); 
		if(!counter[2]) Add(val,(counter[0]+counter[1])*pw[counter[0]]%P);
		Add(val,-L.tr[1]), Add(val,-R.tr[1]);
		Add(val,(counter[1]+2*counter[2])*pw[n-1]%P);
		Add(Ans,(sp[i]-sp[i-1])%P*val%P); 
	}
	up(i,1,n) Add(Ans,-(a[i]+b[i])%P*pw[n-1]%P);
	cout << (Ans%P+P)%P << '\n';
	return 0; 
}
posted @ 2025-11-06 20:00  Hypoxia571  阅读(15)  评论(0)    收藏  举报