P2757 [国家集训队]等差子序列

P2757 国家集训队 等差子序列
考虑有用值域
对于 \(1 \le val_i \le \lceil \frac{N}{2} \rceil\) 那么有用值域是 \([1, 2*val_i]\)
对于 \(\lceil \frac{N}{2} \rceil \lt val_i \le N\) 那么有用值域是 \([2*val_i-N, N]\)
然后我们可以发现,对于一对可行解 \(a + c = 2 * val_i (a \lt val_i \lt c)\)
记录 \(l_i\)\(val_i\) 在有用值域内的前缀和, \(r_i\)\(val_i\) 在有用值域内的后缀和。
那么当所有可行 \(a, c\)\(val_i\) 的同一侧的时候 \(l_i\)\(r_i\)\(2*val_i\) 的倍数。
那么有解只要任意一个 \(val_i\), \(l_i, r_i\) 不为0,\(l_i \not\equiv 0 (\mod (2*val_i))\) 并且 \(r_i \not\equiv 0 (\mod (2*val_i))\)

/*
Name:P2757
Copyright: No
Author: Gensokyo_Alice
Date: 26/9/20/ 09:24
Description:
*/
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <set>
#include <map>

using namespace std;

typedef long long ll;
const ll MAXN = 1e6+10;

ll N, T, val[MAXN], C[MAXN], l[MAXN], r[MAXN];

void add(ll, ll);
ll ask(ll);

int main() {
	ios::sync_with_stdio(false);
	#ifdef ZZCAKIOI
	#endif
	cin >> T;
	while (T--) {
		cin >> N;
		for (ll i = 1; i <= N; i++) {
			cin >> val[i];
			if (val[i] * 2 - 1 > N) l[i] = ask(N) - ask(val[i]*2-N-1);
			else l[i] = ask(2*val[i]-1);
			add(val[i], val[i]);
		}
		for (ll i = 1; i <= N; i++) C[i] = 0;
		for (ll i = N; i >= 1; i--) {
			if (val[i] * 2 - 1 > N) r[i] = ask(N) - ask(val[i]*2-N-1);
			else r[i] = ask(2*val[i]-1);
			add(val[i], val[i]);
		}
		ll flag = 0;
		for (ll i = 1; i <= N; i++) {
			if (l[i] && r[i] && (r[i] % (2 * val[i]) && l[i] % (2 * val[i]))) {
				flag = 1;
			}
		}
		if (flag) puts("Y");
		else puts("N");
	}
	return 0;
}

void add(ll x, ll val) {
	while (x <= N) {
		C[x] += val;
		x += (x & (-x));
	}
}

ll ask(ll x) {
	ll ret = 0;
	while (x) {
		ret += C[x];
		x -= (x & (-x));
	}
	return ret;
}

posted @ 2020-09-26 09:29  Gensokyo_Alice  阅读(143)  评论(3编辑  收藏  举报