CodeForces-1438D Powerful Ksenia(构造)

Powerful Ksenia(构造)

题目链接

Problem statment

Ksenia has an array a a a consisting of n n n positive integers a 1 , a 2 , … , a n a_1, a_2, \ldots, a_n a1,a2,,an.

In one operation she can do the following:

  • choose three distinct indices i , j , k i, j, k i,j,k, and then
  • change all of a i , a j , a k a_i, a_j, a_k ai,aj,ak to a i ⊕ a j ⊕ a k a_i \oplus a_j \oplus a_k aiajak simultaneously, where ⊕ denotes the bitwise XOR operation.

She wants to make all a i a_i ai equal in at most n n n operations, or to determine that it is impossible to do so. She wouldn’t ask for your help, but please, help her!

Input

The first line contains one integer n n n ( 3 ≤ n ≤ 1 0 5 3 \leq n \leq 10^5 3n105) — the length of a a a.

The second line contains n n n integers, a 1 , a 2 , … , a n a_1, a_2, \ldots, a_n a1,a2,,an ( 1 ≤ a i ≤ 1 0 9 ) (1 \leq a_i \leq 10^9) (1ai109) — elements of a a a.

Output

Print YES or NO in the first line depending on whether it is possible to make all elements equal in at most n n n operations.

If it is possible, print an integer m m m ( 0 ≤ m ≤ n ) (0 \leq m \leq n) (0mn), which denotes the number of operations you do.

In each of the next mm lines, print three distinct integers i , j , k , i, j, k, i,j,k, representing one operation.

If there are many such operation sequences possible, print any. Note that you do not have to minimize the number of operations.

题意

给你长度为 n n n的数组 a a a,你能够进行下序操作 ( 最 多 n 次 ) (最多n次) (n)

  • 挑选一个三元组 ( i , j , k ) (i,j,k) (i,j,k)
  • 然后是 a i a_i ai= a j a_j aj= a k a_k ak= a i ⊕ a j ⊕ a k a_i \oplus a_j \oplus a_k aiajak

使得 a a a数组中每个元素都相同,如果能,输出“ Y E S YES YES”,并输出操作数和按顺序输出选择的三元组,如果不能输出" N O NO NO"

思路

我们可以发现进行如下操作:

  1. 选择 ( 1 , 2 , 3 ) (1,2,3) (1,2,3), a 1 = a 2 = a 3 = a 1 ⊕ a 2 ⊕ a 3 a_1=a_2=a_3=a_1 \oplus a_2 \oplus a_3 a1=a2=a3=a1a2a3
  2. 随后选择 ( 3 , 4 , 5 ) (3,4,5) (3,4,5),此时的 a 3 a_3 a3经过上述操作已经变成了 a 1 ⊕ a 2 ⊕ a 3 a_1 \oplus a_2 \oplus a_3 a1a2a3,那么在进行这步操作的时候 a 3 = a 4 = a 5 = a 3 ⊕ a 4 ⊕ a 5 a_3=a_4=a_5=a_3 \oplus a_4 \oplus a_5 a3=a4=a5=a3a4a5 a 3 = a 4 = a 5 = a 1 ⊕ a 2 ⊕ a 3 ⊕ a 4 ⊕ a 5 a_3=a_4=a_5=a_1 \oplus a_2 \oplus a_3 \oplus a_4 \oplus a_5 a3=a4=a5=a1a2a3a4a5
  3. 那么我们一直模仿上序操作一直取到 n − 2 n-2 n2位为止,每步加 2 2 2,那么 a n = a n − 1 = a n − 2 = a 1 ⊕ a 2 ⊕ a 3 ⊕ ⋯ ⊕ a n a_n=a_{n-1}=a_{n-2}= a_1 \oplus a_2 \oplus a_3 \oplus \dots \oplus a_n an=an1=an2=a1a2a3an(奇数). a n − 1 = a n − 2 = a n − 3 = a 1 ⊕ a 2 ⊕ a 3 ⊕ ⋯ ⊕ a n − 1 a_{n-1}=a_{n-2}=a_{n-3}= a_1 \oplus a_2 \oplus a_3 \oplus \dots \oplus a_{n-1} an1=an2=an3=a1a2a3an1(偶数),因为我是从 1 1 1开始枚举的,每次枚举两位,也就是说我 n n n为奇数的时候,枚举到最多的位置为 n − 2 n-2 n2位,偶数的话为 n − 3 n-3 n3
  4. 这时候我们就发现了我们进行上述操作时,如 1 , 2 1,2 1,2两步时, a 1 = a 2 a_1=a_2 a1=a2,同时 a 3 = a 4 a_3=a_4 a3=a4,就是每进行一步操作必有相邻的两个数相等。

因此,得到结论:

  • 如果为奇数,一定能行,我们先模仿 1 , 2 1,2 1,2两步操作,一直取到 n − 2 n-2 n2为止,每次加 2 2 2,然后每次去那两个相邻的数,与 a n a_n an进行异或就行了,总操作数为 ( n − 3 ) / 2 + 1 + ( n − 1 ) / 2 (n-3)/2+1 + (n-1)/2 (n3)/2+1+(n1)/2
  • 如果为偶数的话,由于我们最后一位 a n a_n an没有进行任何操作,因此,我们要判断 a n a_n an是否等于 a n − 1 = a n − 2 = a n − 3 = a 1 ⊕ a 2 ⊕ a 3 ⊕ ⋯ ⊕ a n − 1 a_{n-1}=a_{n-2}=a_{n-3}= a_1 \oplus a_2 \oplus a_3 \oplus \dots \oplus a_{n-1} an1=an2=an3=a1a2a3an1就是数组整体异或是否为 0 0 0就行,如果为 0 0 0说明能够构造,模仿上述操作。如果不为 0 0 0,就一定构造不出来。

代码

#include<bits/stdc++.h>
#define Case int t;scanf("%d",&t);while(t--)
using namespace std;
typedef long long ll;
const int N=1e6+10;
const int M=1e6+10;
ll a[N];
struct node{
    int a,b,c;
}ans[N];
void run(){
    int n;
    scanf("%d",&n);
    int num=0;
    ll sum=0;
    for(int i=1;i<=n;i++){
        scanf("%lld",&a[i]);
        sum^=a[i];
    }
    if(n%2==0&&sum){
        printf("NO\n");
        return ;
    }
    printf("YES\n");
    for(int i=1;i<=n-2;i+=2){
        ans[++num].a=i;
        ans[num].b=i+1;
        ans[num].c=i+2;
    }
    for(int i=1;i<n-1;i+=2){
        ans[++num].a=i;
        ans[num].b=i+1;
        ans[num].c=n;
    }
    printf("%d\n",num);
    for(int i=1;i<=num;i++){
        printf("%d %d %d\n",ans[i].a,ans[i].b,ans[i].c);
    }
}
int main(){
    // Case
    run();
    return 0;
}

道阻且长,且行且珍惜

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值