题解:AT_arc155_c [ARC155C] Even Sum Triplet
前言。
一道还不错的分类讨论题,本身涉及的知识点不多,就是细节比较多,细心点调是没有什么大问题的。
题意简述:给定两个长为
分析。
根据我们小学的知识,我们不难发现,如果保证三个数的和为偶数,那么仅存在两个情况:要么均是偶数,要么一个偶数,两个奇数。
我们先从一个奇数,两个偶数的情况入手。考虑构造。分成两个情况:在
1 2 5 7 //因为1,2,5的和为偶数,所以符合条件,交换1和5的位置。
5 2 1 7 //因为2,1,7的和为偶数,所以符合条件,交换位置。
5 7 2 1 //因为5,7,2的和为偶数,所以符合条件,交换位置。
2 5 7 1 //注意此时存着一个新的区间即2 5 7。
事实上,我们不难将其拓展到一般情况下,因为在其中的交换对于任意的这种情况都是可以构造出来的。同理,如果我们将
2 4 5 7 //4+5+7为偶数,所以交换。
2 5 7 4 //此时2+7+5为偶数,构成一个新的。
仍然可以拓展到一般情况。所以我们可以得出结论:相邻的三个数中有一个偶数,两个奇数时,这两个奇数可以一起向左边或者右边移动(右边和上面的左边同理)一位,构造出一个新的合法区间。那么我们在任意交换的过程中,考虑每一个数的相对位置的变化情况。我们不妨设有两个奇数
注意到,在一个偶数,两个奇数的情况下,偶数的顺序是不会受到影响的,而可以改变相对顺序的只能是三个偶数的情况,此时因为均是偶数,所以可以任意交换,使得其相对顺序改变。此时算法就很显然了,先去判断一下是否存在合法区间然后分成是否存在三个偶数的合法区间,如果
代码如下,仅供参考:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int n,a[200005],b[200005];
int a2[200005],b2[200005],flag;
int tot1,tot2,sum;
template <typename T> void read(T &x){
x = 0;
bool f = 0;
char c = getchar();
while (c < '0' || c > '9') f |= c == '-', c = getchar();
while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
if (f) x = -x;
}
template <typename T> void write(T x){
if (x < 0) putchar('-'), x = -x;
if (x < 10) putchar(x + '0');
else write(x / 10), putchar(x % 10 + '0');
}
bool cheak1(){
sum=0;
for(int i=1;i<=n-2;i++){
if(((a[i]&1)+(a[i+1]&1)+(a[i+2]&1))==2){
tot1=tot2=0;
//判断一些偶数的移动情况。
for(int i=1;i<=n;i++){
if(!(a[i]&1)){
a2[++tot1]=a[i];
}
if(!(b[i]&1)){
b2[++tot2]=b[i];
}
}
if(tot1==2&&a2[1]!=b2[1]){//只有两个偶数
return 0;
}
return 1;
}
}
for(int i=1;i<=n;i++){
a2[i]=a[i];
b2[i]=b[i];
//记得还原一些。
}
for(int i=1;i<=n;i++){
if((a2[i]&1)&&(a2[i]!=b2[i])){
return 0;
}//奇数不对于,相对位置不可改变。
if(a2[i]&1){
sort(a2+sum,a2+i);
sort(b2+sum,b2+i);
for(int j=sum;j<=i-1;j++){
if(a2[j]!=b2[j]){
return 0;
}
}
if(((i-1)-sum)==2&&a[i-1]!=b[i-1]){
return 0;
}
sum=i;
}
}
sort(a2+sum,a2+n+1);
sort(b2+sum,b2+n+1);
if(n-sum==2&&a2[n]!=b2[n]){
return 0;
}
return 1;
}
int main(){
read(n);
for(int i=1;i<=n;i++){
read(a[i]);
a2[i]=a[i];
}
for(int i=1;i<=n;i++){
read(b[i]);
b2[i]=b[i];
}
//记录序列。
sort(a2+1,a2+n+1);
sort(b2+1,b2+n+1);
//排序用来判断是否存在的数相同。
for(int i=1;i<=n;i++){
if(a2[i]!=b2[i]){
printf("No");
return 0;
}//有的数个数不同,不能构造。
}
for(int i=1;i<=n;i++){
if(a[i]&1){
flag=1;
break;
}//奇数。
}
if(!flag){
cout<<"Yes\n";
return 0;
}//均是一种数合法的情况,肯定可以。
if(!cheak1()){
cout<<"No\n";
return 0;
}
for(int i=1;i<=n;i++){
swap(a[i],b[i]);
}
if(!cheak1()){
cout<<"No\n";
return 0;
}
cout<<"Yes\n";
return 0;
}
后记。
大家如有疑问,可以在评论区提出,我会尽力解答的。