https://codeforces.com/contest/1474/problem/D
質問の意味:n個の数字で、0ではない隣接する数字を取り出して、同時に1ずつ減らすことができます。ヒープが0の場合、消えることはありません。現時点では、操作する機会は最大で1つです。隣接する2つの番号の位置を入れ替えて、すべての番号を0にすることができるかどうかを尋ねます。
アイデア:最初に、エンドポイントが次の値未満である必要があることを確認します。そうでない場合、それは間違いなく真実ではありません。
したがって、a2> = a1、減算後、a2 = a2-a1;この時点で、a2が終点になり、同じ原理は、a3> =がこの時点でのみ確立できることを示しています。
したがって、同じことがテールから開始する場合にも当てはまります。
次に、プレフィックスを使用して中間プロセスを記録します。つまり、プレフィックスは、隣接するものを差し引くことができることを示すために使用され、その後、この時点でどれだけ遅れているかを示します。接尾辞は同じです。
pre [i-1]> a [i]が途中で検出された場合、これら2つの隣接するものが削減されると、a [i-1]が「空の島」になることを意味します。対象の要件を満たすことができません。この場合、レコードはpre [i] = inf / 2; [Why / 2です。これはバックエンドの先頭にも当てはまるため、隣接するアイテムを交換するときにプレフィックスとサフィックスが等しいかどうかを判断する必要があります。そして、suf [] = inf / 2の場合、等しくできない2つの数値はinf = infになります-誤った判断につながります]
次に、列挙して、プレフィックスとサフィックスのpre [i]とsuf [i +1]が同じかどうかを判断します。同じことが大丈夫です。別の方法で交換してみて、できるかどうかを確認してください。
#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=2e5+1000;
typedef long long LL;
LL a[maxn],pre[maxn],suf[maxn];
const LL inf=1e18;
int main(void)
{
cin.tie(0);std::ios::sync_with_stdio(false);
LL t;cin>>t;
while(t--){
LL n;cin>>n;
for(LL i=0;i<=n+10;i++) pre[i]=suf[i]=0;
for(LL i=1;i<=n;i++) cin>>a[i];
for(LL i=1;i<=n;i++){
if(a[i]>=pre[i-1]){
pre[i]=a[i]-pre[i-1];
}
else pre[i]=inf/2;
}
for(LL i=n;i>=1;i--){
if(a[i]>=suf[i+1]){
suf[i]=a[i]-suf[i+1];
}
else suf[i]=inf;
}
bool flag=1;
for(LL i=1;i<=n-1;i++){
if(pre[i]==suf[i+1]){
flag=0;
break;
}
else{
///交换相邻石堆
LL A=a[i];LL B=a[i+1];
if(A>=suf[i+2]&&B>=pre[i-1]){
A-=suf[i+2];B-=pre[i-1];
LL cnt=A-B;
if(cnt==0){
flag=0;
break;
}
}
}
}
if(flag==0){
cout<<"YES"<<endl;
}
else cout<<"NO"<<endl;
}
return 0;
}