Codeforces Round #696 (Div. 2)


C - Array Destruction

传送门

题意:给一个长度为 n n n的序列,问能否找出一个 x x x?,有 a i + a j = x a_i+a_j=x ai+aj=x,消去 a i , a j a_i,a_j ai,aj,然后 x x x变成 m a x ( a i , a j ) max(a_i,a_j) max(ai,aj) n 2 \frac{n}{2} 2n次操作后消除数组所有数。

思路:每次必须选择当前序列最大的数,因为如果不选之后就无法再消除这个数了,所以先从小到大排序,第一次操作我们枚举前 n − 1 n-1 n1个数和 a n a_n an的和作为第一个 x x x的情况,之后用一个set维护当前序列的最大值,如果有数加上最大值等于 x x x,继续往下做,否则当前情况不成立。

AC代码:

#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
#define ALL(x) (x).begin(), (x).end()
typedef vector<int> VI;
typedef pair<int,int> pii;
typedef long long ll;
typedef unsigned long long ull;
const int N=2010;
 
int a[N];
int ans1[N],ans2[N];
multiset<int> S;
 
void solve()
{
	int n;
	cin>>n;
	n*=2;
	rep(i,1,n) cin>>a[i];
 
	sort(a+1,a+1+n);
 
	
	int cnt=0;
 
	rep(i,1,n-1)
	{
		cnt=0;
		ans1[++cnt]=a[n];
		ans2[cnt]=a[i];
		int maxv=a[n];
 
		S.clear();
 
		rep(j,1,n-1)	
			if(j!=i) S.insert(a[j]);
 
		while(SZ(S))
		{
			auto it1=S.end();
			it1--;
			S.erase(it1);
 
			int temp=*it1;
			auto it2=S.find(maxv-temp);
 
			if(it2!=S.end())
			{
				ans1[++cnt]=temp;
				ans2[cnt]=maxv-temp;
				S.erase(it2);
				maxv=temp;
			}
			else break;
		}
 
		if(cnt==n/2) break;
	}	
 
	if(cnt==n/2)
	{
		cout<<"YES\n";
		cout<<ans1[1]+ans2[1]<<endl;
		rep(i,1,cnt)
			cout<<ans2[i]<<" "<<ans1[i]<<endl;
	}
	else cout<<"NO\n";
}	
 
int main()
{
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	int T; cin>>T;
	while(T--) solve();
	return 0;
}

D. Cleaning

传送门

题意:给出n堆石头,第 i i i堆有 a i a_i ai个石头,现在需要清空这些石头,可执行的操作为:

  1. 选择两个相邻的堆,如果它们都不是空的,从每个堆中移出一块石头。
  2. 在开始清理前,可以选择相邻的两堆并进行交换。(仅限一次)

问能否将这n堆石头清空?

思路:要全变成 0 0 0 a i − 1 a_{i-1} ai1必须小于 a i a_i ai(从左到右消除)或 a i + 1 a_{i+1} ai+1必须小于 a i a_i ai(从右到左消除),维护两个数组, b i b_i bi是处理完左边 1 ∼ i − 1 1\sim i-1 1i1堆后第 i i i堆的石子, c i c_i ci是处理完右面 i + 1 ∼ n i+1 \sim n i+1n堆后第i堆的石子,如果 b n b_n bn 0 0 0,则 a a a可以全变为 0 0 0,如果不行,考虑交换的情况,交换 a i a_i ai a i + 1 a_{i+1} ai+1不影响 b i − 1 b_{i-1} bi1 c i + 1 c_{i+1} ci+1,所以交换 a i a_i ai a i + 1 a_{i+1} ai+1,只需要判断 b i − 1 , a i + 1 , a i , c i + 1 b_{i-1},a_{i+1},a_{i},c_{i+1} bi1,ai+1,ai,ci+1的合法性,就可以判断 a i a_i ai能否全变成 0 0 0

AC代码:

#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
#define ALL(x) (x).begin(), (x).end()
typedef vector<int> VI;
typedef pair<int,int> pii;
typedef long long ll;
typedef unsigned long long ull;
const int N=2e5+10;
 
ll a[N],b[N],c[N];

bool check(ll a,ll b,ll c,ll d)
{
	b-=a;
	if(b<0) return 0;
	c-=b;
	if(c<0) return 0;
	d-=c;
	return d==0;
}
 
void solve()
{
    memset(b,0,sizeof(b));
    memset(c,0,sizeof(c));
	int n;
	cin>>n;
    
	rep(i,1,n)
	{
		cin>>a[i];
		if(a[i]<b[i-1]) b[i]=1e18;
		else b[i]=a[i]-b[i-1];
	}
 
	per(i,n,1)
	{
		if(a[i]<c[i+1]) c[i]=1e18;
		else c[i]=a[i]-c[i+1];
	}
    
	if(b[n]==0) cout<<"YES\n";
	
	else
	{
		bool flag=0;
		rep(i,1,n-1)
		{
			if(check(b[i-1],a[i+1],a[i],c[i+2]))
			{
				flag=1;
				cout<<"YES\n";
				break;
			}
		}
		if(!flag) cout<<"NO\n";
	}
 
	
}
 
int main()
{
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	int T; cin>>T;
	while(T--) solve();
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值