题解 玩游戏

传送门

考场上用了一个平均 \(O(n)\) ,最坏 \(O(n^2)\) 的方法过掉了

先说说这个方法:
取一个左指针,一个右指针,初始位置都在 \(k\)
每次让右指针在满足 \(tot \leqslant 0\) 的前提下尽量右移
当发现右指针移动不了时,尝试把左指针左移一位
如果发现移过去会让 \(tot > 0\) ,就不断左移右指针到第一个可以让左指针左移的位置
如果没有这样的位置,puts("No");
如果有,就移过去
重复上述过程直到两指针均到达边界
但可以构造数据让右指针的移动是 \(n^2\) 级别的
其实可以用主席树处理退化,复杂度严格 \(nlogn\)
但战神试了发现慢了6倍

至于题解做法:
从位置 \(k\) 向左右两边分别做前缀和
发现如果能移到一个前缀和更小的地方就一定会移
重复此过程,两指针均会移到前缀和最小的位置
然后应该是可以可以把数组倒过来,从两边向位置 \(k\)
如果也能走到最小值的位置即为合法

Code:

#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define ll long long 
#define fir first
#define sec second
#define make make_pair
#define reg register int 
//#define int long long 

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline ll read() {
	ll ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, k;
ll a[N], sum[N];

namespace force{
	queue< pair<int, int> > q;
	pair<int, int> t;
	void solve() {
		while (q.size()) q.pop();
		q.push(make(k, k));
		while (q.size()) {
			t=q.front(); q.pop();
			if (t.fir==1 && t.sec==n && sum[t.sec]-sum[t.fir]<=0) {puts("Yes"); return ;}
			if (t.fir>1 && sum[t.sec]-sum[t.fir-1]<=0) {
				if (t.fir-1==1 && t.sec==n) {puts("Yes"); return ;}
				q.push(make(t.fir-1, t.sec));
			}
			if (t.sec<n && sum[t.sec+1]-sum[t.fir]<=0) {
				if (t.fir==1 && t.sec+1==n) {puts("Yes"); return ;}
				q.push(make(t.fir, t.sec+1));
			}
		}
		puts("No");
	}
}

namespace task1{
	void solve() {
		int l=k, r=k;
		ll tot=0;
		while (l>1 || r<n) {
			//cout<<"loop"<<endl;
			while (r<n && tot+a[r+1]<=0) tot+=a[r+1], ++r;
			//cout<<"r: "<<r<<endl;
			if (l>1) {
				if (tot+a[l]<=0) tot+=a[l], --l;
				else {
					while (r>k) {
						tot-=a[r], --r;
						if (tot+a[l]<=0) {tot+=a[l], --l; goto jump;}
					}
					puts("No"); return ;
					jump: ;
				}
				//cout<<"now: "<<l<<' '<<r<<' '<<tot<<endl;
			}
			else if (r<n) {puts("No"); return ;}
		}
		//cout<<l<<' '<<r<<' '<<tot<<endl;
		puts("Yes");
		//if (l==1 && r==n && tot<=0) puts("Yes");
		//else puts("error");
	}
}

signed main()
{
	int T;
	
	T=read();
	while (T--) {
		n=read(); k=read();
		for (reg i=1; i<=n; ++i) a[i]=read(), sum[i]=sum[i-1]+a[i];
		//force::solve();
		task1::solve();
	}
	
	return 0;
}
posted @ 2021-08-12 18:56  Administrator-09  阅读(6)  评论(0编辑  收藏  举报