zoukankan      html  css  js  c++  java
  • CF1438D

    首先,要发现两个性质。
    1.一次操作其实相当于把三个数变为相同的一个数。
    2.每次操作前后整个数列的异或和不变。
    第一个性质比较显然,证明一下第二个性质。
    设原来这三个数分别为 (x)(y)(z)
    操作前,它们的异或和为 (x oplus y oplus z)
    操作后,这三个数都变成了 (x oplus y oplus z)
    它们的异或和仍然为 (x oplus y oplus z)

    先考虑数列长度为奇数的情况。
    首先,把相邻的三个数操作一下,每次操作的起点即为上次操作的终点。
    操作后,整个数列就变为了若干段长度为2的相同的数,以及最后一段长度为3的相同的数。
    这样,把最后一个数拿出来,与前面的每两个相同的数都做一次操作即可。
    操作次数为 (n-2) 次,可以通过。

    接下来,考虑数列长度为偶数的情况。
    如果是有解的,且数列长度为偶数,那么最后整个数列的异或和一定为0。
    根据上面的性质2,可以得到数列操作前的异或和也一定为0,同理,整个数列在每一步操作后的异或和也为0。
    现在已经可以判断无解了。
    若有解,考虑把最后一个数单独拿出来,把前面的 (n-1) 个数按照奇数的做法做一遍。
    因为整个数列在每一步操作后的异或和一定为0,又因为数列的前 (n-1) 个数已经相等了,所以,它们也一定和最后一个数相等。
    操作次数为 (n-3) 次。

    #include<iostream>
    #include<cstdlib>
    #include<cstdio>
    using namespace std;
    const int N=1e5+10;
    int n,a[N],sum;
    int main()
    {
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++) scanf("%d",&a[i]),sum^=a[i];
    	if(n%2==0&&sum) puts("NO"),exit(0);
    	if(n%2==0) n--;
    	printf("YES
    %d
    ",n-2);
    	for(int i=1;i<=n-2;i+=2) printf("%d %d %d
    ",i,i+1,i+2);
    	for(int i=1;i<=n-4;i+=2) printf("%d %d %d
    ",i,i+1,n);
    	return 0;
    }
    
  • 相关阅读:
    vijos1194 Domino
    vijos1603迷宫
    怎样实现App安装来源追踪
    怎样实现App安装来源追踪
    怎么在Chrome和Firefox浏览器中清除HSTS设置?
    怎么在Chrome和Firefox浏览器中清除HSTS设置?
    element UI排坑记(一):判断tabs组件是否切换
    ZooKeeper分布式锁的实现原理
    ZooKeeper分布式锁的实现原理
    TensorFlow框架 入门笔记
  • 原文地址:https://www.cnblogs.com/zhs1/p/14266454.html
Copyright © 2011-2022 走看看