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 n−1个数和 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个石头,现在需要清空这些石头,可执行的操作为:
- 选择两个相邻的堆,如果它们都不是空的,从每个堆中移出一块石头。
- 在开始清理前,可以选择相邻的两堆并进行交换。(仅限一次)
问能否将这n堆石头清空?
思路:要全变成 0 0 0, a i − 1 a_{i-1} ai−1必须小于 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 1∼i−1堆后第 i i i堆的石子, c i c_i ci是处理完右面 i + 1 ∼ n i+1 \sim n i+1∼n堆后第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} bi−1和 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} bi−1,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;
}