标签给的是DP但是又双叒叕和DP没有关系。
这道题读一会儿之后就会自然而然的感觉和前缀后缀有关系。因为如果能够相邻的正好两两相消,那么我们不管从前往后还是从后往前,两两相减一定正好消完,那么除了问题就说明中间的某一处对不上了。但是他的前面和后面都是对的(因为只能换一组,如果前后还有问题那说明要换的不止一组,肯定不行了)。做一个前缀再做一个后缀,然后枚举一下交换两个之后能否相消。如果相消了那就说明对了。
这里要注意,对上的时候要看一下是不是负数相消,因为移石头不可能是负的,所以负数对负数消掉了也没用,还是NO,这点前面没发现WA了好久,叹气。
下附代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 #define ll long long 3 using namespace std; 4 ll a[200005],n; 5 ll st[200005],ed[200005],stf[200005],edf[200005]; 6 int main(){ 7 int T; 8 scanf("%d",&T); 9 while (T--){ 10 scanf("%lld",&n); 11 for (int i=1; i<=n; i++){ 12 scanf("%lld",&a[i]); 13 } 14 ed[n+1]=0; 15 for (int i=n; i>=1; i--){ 16 if (ed[i+1]==-1 || a[i]<ed[i+1]){ 17 ed[i]=-1; 18 } 19 else { 20 ed[i]=a[i]-ed[i+1]; 21 } 22 } 23 st[0]=0; 24 for (int i=1; i<=n; i++){ 25 if (st[i-1]==-1 || a[i]<st[i-1]){ 26 st[i]=-1; 27 } 28 else { 29 st[i]=a[i]-st[i-1]; 30 } 31 } 32 int flag=0; 33 if (st[n]==0) { 34 printf("YES "); 35 flag=1; 36 } 37 else { 38 for (int i=1; i<=n-1; i++){ 39 if (st[i-1]==-1 || ed[i+2]==-1) continue; 40 if (a[i+1]>=st[i-1] && a[i]>=ed[i+2] && a[i+1]-st[i-1]==a[i]-ed[i+2]){ 41 printf("YES "); 42 flag=1; 43 break; 44 } 45 } 46 } 47 if (!flag) printf("NO "); 48 } 49 }