首页 > 其他分享 >Codeforces Round #822 (Div. 2)

Codeforces Round #822 (Div. 2)

时间:2022-09-26 13:44:28浏览次数:73  
标签:mid nw2 int res sum pos Codeforces Div 822

D. Slime Escape

被 greedy 整破防了。

image

这是转换后的题面。

考虑使用调整法构造,记 2 个序列分别为 \(f,g\),那么一种调整法是,\(f\) 加了没事就加了不管,否则我们再考虑往当前已经构造的序列的最大值的后方加一段正贡献的 \(g\)。

显然这个很对了,但有点假(

我们考虑前缀和,那么前面的要尽可能大,一个方向的一味扩展有时候可能当前没事但会导致后面出事。

那么,我们就要当前能加多大就多大,这个加是按当前 \(f\) 的正负分类的。若 \(f\) 为正,显然直接加,然后再看看 \(g\) 那边能否有正贡献。因为初始越大,所能在 \(g\) 得到的贡献期望越大。若 \(f\) 为负,我们可以看看拿当前的往 \(g\) 扩展正贡献,然后再看看能不能不出事。

然后 \(O(n^2)\) 到 \(O(n\log n)\) trick 一下二分 + ST 表就好了。

#include <bits/stdc++.h>
#define int long long
#define pb push_back
using namespace std;
const int N=(int)(2e5+5);
int a[N],n,p,f[N],g[N],tot1,tot2,st1[23][N],st2[23][N],stp[23][N],sum[N];
// mi:[nw2+1,i]+x>=0
// sum[j]-sum[nw2]+x>=0 sum[j] 为 min
// sum[j]>=sum[nw2]-x 前提条件。 
// sum:[nw2+1,i]+x 取 max
// \max{sum[i]-sum[nw2]+x}
// 1. 二分找到最远扩展到哪里
// 2. 取扩展区间最大 

int qrymi(int l,int r) {
	int qwq=log2(r-l+1);
	return min(st1[qwq][l],st1[qwq][r-(1<<qwq)+1]);
}

int qrymx(int l,int r) {
	int qwq=log2(r-l+1);
	return max(st2[qwq][l],st2[qwq][r-(1<<qwq)+1]);
}

int qrymxp(int l,int r) {
	int qwq=log2(r-l+1);
	if(st2[qwq][l]>=st2[qwq][r-(1<<qwq)+1]) return stp[qwq][l];
	return stp[qwq][r-(1<<qwq)+1];
}

void sol() {
	cin>>n>>p;
	for(int i=1;i<=n;i++) cin>>a[i];
	tot1=tot2=0;
	for(int i=p+1;i<=n;i++) f[++tot1]=a[i];
	for(int i=p-1;i>=1;i--) g[++tot2]=a[i];
	for(int i=1;i<=tot2;i++) sum[i]=sum[i-1]+g[i];
	for(int i=1;i<=tot2;i++) {
		st1[0][i]=sum[i]; st2[0][i]=sum[i]; stp[0][i]=i;
	}
	for(int i=1;(1<<i)<=tot2;i++) {
		for(int j=1;j+(1<<i)-1<=tot2;j++) {
			st1[i][j]=min(st1[i-1][j],st1[i-1][j+(1<<(i-1))]);
			st2[i][j]=max(st2[i-1][j],st2[i-1][j+(1<<(i-1))]);
			if(st2[i][j]==st2[i-1][j]) stp[i][j]=stp[i-1][j];
			else stp[i][j]=stp[i-1][j+(1<<(i-1))];
		}
	}
	int res=a[p],nw1=0,nw2=0;
	bool ok=1;
	while(nw1<tot1) {
		if(f[nw1+1]>=0) {
			res+=f[nw1+1]; ++nw1;
			
//			for(int i=nw2+1;i<=tot2;i++) {
//				if(x+g[i]<0) break ;
//				x+=g[i];
//				if(x>mx) {
//					mx=x; pos=i;
//				}
//			}
			int x=res,mx=0,pos=0;
			int l=nw2+1,r=tot2;
			while(l<=r) {
				int mid=(l+r)>>1;
				if(qrymi(nw2+1,mid)-sum[nw2]+res>=0) l=mid+1,pos=mid;
				else r=mid-1;
			}
			if(!pos) {
				continue ;
			}
			mx=qrymx(nw2+1,pos)-sum[nw2]+res;
			pos=qrymxp(nw2+1,pos);
			if(mx>res) {
				res=mx; nw2=pos;
			}
		} else {
			int x=res,mx=0,pos=0;
			int l=nw2+1,r=tot2;
			while(l<=r) {
				int mid=(l+r)>>1;
				if(qrymi(nw2+1,mid)-sum[nw2]+res>=0) l=mid+1,pos=mid;
				else r=mid-1;
			}
			if(!pos) {
				if(res+f[nw1+1]<0) {
					ok=0; break ;
				}
				res+=f[nw1+1]; ++nw1;
				continue ;
			}
			mx=qrymx(nw2+1,pos)-sum[nw2]+res;
			pos=qrymxp(nw2+1,pos);
			if(mx>res) {
				res=mx; nw2=pos;
			}
			if(res+f[nw1+1]<0) {
				ok=0; break ;
			}
			res+=f[nw1+1]; ++nw1;
		}
	}
	if(nw1!=tot1) ok=0;
	if(ok) {
		cout<<"YES\n"; return ;
	}
	tot1=tot2=0;
	for(int i=p-1;i>=1;i--) f[++tot1]=a[i];
	for(int i=p+1;i<=n;i++) g[++tot2]=a[i];
	for(int i=1;i<=tot2;i++) sum[i]=sum[i-1]+g[i];
	for(int i=1;i<=tot2;i++) {
		st1[0][i]=sum[i]; st2[0][i]=sum[i]; stp[0][i]=i;
	}
	for(int i=1;(1<<i)<=tot2;i++) {
		for(int j=1;j+(1<<i)-1<=tot2;j++) {
			st1[i][j]=min(st1[i-1][j],st1[i-1][j+(1<<(i-1))]);
			st2[i][j]=max(st2[i-1][j],st2[i-1][j+(1<<(i-1))]);
			if(st2[i][j]==st2[i-1][j]) stp[i][j]=stp[i-1][j];
			else stp[i][j]=stp[i-1][j+(1<<(i-1))];
		}
	}
	res=a[p],nw1=0,nw2=0;
	ok=1;
	while(nw1<tot1) {
		if(f[nw1+1]>=0) {
			res+=f[nw1+1]; ++nw1;
			
//			for(int i=nw2+1;i<=tot2;i++) {
//				if(x+g[i]<0) break ;
//				x+=g[i];
//				if(x>mx) {
//					mx=x; pos=i;
//				}
//			}
			int x=res,mx=0,pos=0;
			int l=nw2+1,r=tot2;
			while(l<=r) {
				int mid=(l+r)>>1;
				if(qrymi(nw2+1,mid)-sum[nw2]+res>=0) l=mid+1,pos=mid;
				else r=mid-1;
			}
			if(!pos) {
				continue ;
			}
			mx=qrymx(nw2+1,pos)-sum[nw2]+res;
			pos=qrymxp(nw2+1,pos);
			if(mx>res) {
				res=mx; nw2=pos;
			}
		} else {
			int x=res,mx=0,pos=0;
			int l=nw2+1,r=tot2;
			while(l<=r) {
				int mid=(l+r)>>1;
				if(qrymi(nw2+1,mid)-sum[nw2]+res>=0) l=mid+1,pos=mid;
				else r=mid-1;
			}
			if(!pos) {
				if(res+f[nw1+1]<0) {
					ok=0; break ;
				}
				res+=f[nw1+1]; ++nw1;
				continue ;
			}
			mx=qrymx(nw2+1,pos)-sum[nw2]+res;
			pos=qrymxp(nw2+1,pos);
			if(mx>res) {
				res=mx; nw2=pos;
			}
			if(res+f[nw1+1]<0) {
				ok=0; break ;
			}
			res+=f[nw1+1]; ++nw1;
		}
	}
	if(nw1!=tot1) ok=0;
	if(ok) {
		cout<<"YES\n"; return ;
	}
	cout<<"NO\n";
}

signed main() {
	cin.tie(0); ios::sync_with_stdio(false);
	int T; cin>>T; while(T--) sol();
	return 0;
} 
/*
调整
若<0
调整前面最大的向另一端扩展最大。
*/ 

标签:mid,nw2,int,res,sum,pos,Codeforces,Div,822
From: https://www.cnblogs.com/xugangfan/p/16730582.html

相关文章

  • Codeforces Round #822
    目录写在前面ABCDEF写在最后写在前面比赛地址:https://codeforces.com/contest/1734。复健后第一场div2,感觉有19年水平了。哈哈。A\(t\)组数据,每组数据给定一长......
  • Codeforces Round #822 (Div. 2)
    比赛链接CodeforcesRound#822(Div.2)D.SlimeEscape给一个长度为\(n\)的序列以及一个\(k\),表示当前位于\(k\)这个位置,要求该位置的数往左或者右,每次只能加上......
  • Codeforces Round #822 (Div. 2) D
    https://codeforces.com/contest/1734/problem/D题意有n只史莱姆,每只都有一个值,其中第k只被你控制,你希望能走到0或n+1这两个位置,也就是说遇到路上的史莱姆需要......
  • CodeForces 比赛记录
    带星号的表示vp。\(*\)CFRound601Div.1做出A和B1。B2.SendBoxestoAlice(HardVersion)考虑\(a\)的前缀和数列\(S\),在\(a\)中移动一个数,相当于在\(S......
  • Codeforces Round #822 D,E
    E.RectangularCongruence我们考虑对ar1,c1+ar2,c2≢ar1,c2+ar2,c1(modn)(同余情况下不同也是可以同时加任意数的可以感性理解一下)ar1,c1-ar1,c2≢ar2,c1......
  • CF Round 822 Div2 题解
    比赛链接A题SelectThreeSticks(签到)给定\(n\)根木棒,第\(i\)根木棒的长度为\(a_i\)。现在我们可以进行操作,每次操作选定一根木棒,将其长度增高或减少1。问至少需......
  • Codeforces Round #822 Div.2 整场题解
    目前还有E,F没有更新。A.SelectThreeSticks直接对\(a\)排序,选出来的木棍一定是相邻三项,都往中间靠更优。B.Bright,Nice,Brilliant最优方案就是每一行第一个......
  • Codeforces Round #640 (Div. 4) D. Alice, Bob and Candies
    CodeforcesRound#640(Div.4)翻译岛田小雅D.Alice,BobandCandies出题人MikeMirzayanov\(n\)个糖果排成一排,从左到右分别被编号为\(1\)到\(n\)。第\(i\)......
  • Roadside Trees (Simplified Edition) CodeForces - 265B
    RoadsideTrees(SimplifiedEdition)CodeForces-265B松鼠Liss喜欢坚果。一条街上有n棵树(从西到东编号为1到n),每棵树的顶部都有一颗美味的坚果。树的高度我很高。......
  • Nikita and string CodeForces - 877B
    NikitaandstringCodeForces-877B有一个全由a和b组成的字符串,可以切成三部分。满足如下规则:第一部分只包含a或者是空串。第二部分只包含b或者是空串。第三部分只......