Codeforces-1474-D (思维-消数问题)

本文详细介绍了如何解决一道关于移除石头的编程问题,该问题允许进行特定操作并使用一次超级能力(交换相邻两堆)。作者分享了两种策略(从左到右和从右到左消除)以及解题思路,并提供了C++代码实现。文章强调了在判断解决方案可行性时需要注意的特殊情况。
摘要由CSDN通过智能技术生成

题目

传送门https://codeforces.com/contest/1474/problem/D

During cleaning the coast, Alice found n piles of stones. The i-th pile has ai stones.
Piles i and i+1 are neighbouring for all 1≤i≤n−1. If pile i becomes empty, piles i−1 and i+1 doesn’t become neighbouring.
Alice is too lazy to remove these stones, so she asked you to take this duty. She allowed you to do only the following operation:

  • Select two neighboring piles and, if both of them are not empty, remove one stone from each of them.

Alice understands that sometimes it’s impossible to remove all stones with the given operation, so she allowed you to use the following superability:

  • Before the start of cleaning, you can select two neighboring piles and swap them.

Determine, if it is possible to remove all stones using the superability not more than once.

思路

这题比赛时没做出来……

  • 看评论有个这样的解法:
    在这里插入图片描述
  • 还有题解的做法:
    在这里插入图片描述
  • 注意

case 0 那里不能单纯判断 s[n]==0,我一开始这样写的,一直 WA,调了好久才发现……因为还需要 Smark 显示整个过程未出现负数,此时 s[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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值