トピック
ポータルhttps://codeforces.com/contest/1474/problem/D
海岸を掃除している間、アリスはn個の石の山を見つけました。i番目の山にはai石があります。
杭iとi + 1は、すべて1≤i≤n-1で隣接しています。パイルiが空になった場合、パイルi-1とi +1は隣接しません。
アリスは怠惰すぎてこれらの石を取り除くことができないので、彼女はあなたにこの義務を負うように頼みました。彼女はあなたに次の操作だけをすることを許可しました:
- 隣接する2つの杭を選択し、両方が空でない場合は、それぞれから1つの石を取り除きます。
アリスは、与えられた操作ですべての石を取り除くことが不可能な場合があることを理解しているので、彼女はあなたに次の超能力を使用することを許可しました:
- クリーニングを開始する前に、隣接する2つのパイルを選択して交換できます。
スーパーアビリティを使用してすべての石を1回だけ除去できるかどうかを判断します。
アイデア
この質問は競技中に行われなかった...
- コメントを見ると、次のような解決策があります。
- 問題を解決する方法もあります。
- 注意
ケース0簡単に判断できない
s[n]==0
、書き始めた、彼はWAで、長い間チューニングして見つけただけで……プロセス全体を表示するのに必要なSmarks[n]
は現時点ではネガティブに見えないので有効です値。
コード
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
#define N 200//005
int T,n,a[N];
int s[N],p[N],Smark,Pmark;
int main()
{
scanf("%d",&T);
while (T--) {
scanf("%d",&n);
for (int i=1; i<=n; i++)
scanf("%d",&a[i]);
//从左往右依次消,消到出现负数或者消完为止,用 Smark 记录一下情况
s[0]=0;
Smark=n+1;
for (int i=1; i<=n; i++) {
s[i]=a[i]-s[i-1];
if (s[i]<0) {
Smark=i;
break;
}
}
//从右往左依次消,消到出现负数或者消完为止,用 Pmark 记录一下情况
p[n+1]=0;
Pmark=0;
for (int i=n; i>=1; i--) {
p[i]=a[i]-p[i+1];
if (p[i]<0) {
Pmark=i;
break;
}
}
//case0 消完了,不需要调换
if (Smark==n+1 && s[n]==0) {
puts("YES");
continue;
}
//case1 从左往右和从右往左第一次出错的点相聚远,肯定无法只调换相邻两个而成功
//好像这一类不需要单独拎出来讨论,因为这种情况下面自动跳过for循环
if (Smark<Pmark-1) {
puts("NO");
continue;
}
//case2 判断能否通过调换相邻两个而成功
int fail=1;
for (int i=Smark; i+1>=Pmark; i--) if (i>0 && i<n) {
swap(a[i],a[i+1]);
//a[i]= s[i-1] + (a[i]-s[i-1])
//a[i+1]= p[i+2] + (a[i+1]-p[i+2])
if (a[i]-s[i-1]>=0 && a[i+1]-p[i+2]>=0 && a[i]-s[i-1]==a[i+1]-p[i+2] && s[i-1]>=0 && p[i+2]>=0) {
fail=0;
break;
}
swap(a[i],a[i+1]);
}
puts(fail ? "NO" : "YES");
}
return 0;
}