嘘~ 正在从服务器偷取页面 . . .

CF1572B Xor of 3 题解


CF1572B Xor of 3 题解

题目链接:Xor of 3

题意

给出一个 \(01\) 序列,一次操作可以选择连续的三个数,把它们都变成它们的异或和。

问能否在 \(n\) 次以内把所有数变成 \(0\)​,输出方案(操作 \(i\) 则修改 \(a_i,~a_{i+1},~a_{i+2}\)

输入格式

多组数据,每组数据给出 \(n\)\(n\) 个数。

输出格式

有解输出一行 YES ,否则输出 NO

如果有解,输出一行表示步骤数(可以不是最少次数),接着一行若干个数表示操作位置

数据范围

\(3 \le \sum n \le 2\times10^5\)

感觉这道题在哪里听过思路了,今天找到原题了。思路还是比较有意思的。(upd.其实是 CF1438D

因为题目要全部变成 \(0\) ,所以与异或和性质就显得十分关键。

容易发现,每次操作后所有数的异或和不会改变,因此异或和为 \(0\) 是有解的一个必要条件(但是不充分)

首先考虑 \(n\) 为奇数的情况,如果我们在 \(n-2,~n-4,~\cdots,~1\)​ 分别操作一次

此时 \(a_1=0\) ,且其他的数呈现 AABBCCDD 的状态,即 \(a_{2k}=a_{2k+1}\)

接着我们再对 \(1,~3,~\cdots,~n-2\) 分别操作一次,则序列就会变成全 \(0\)​ 。

\(n\) 为偶数的情况也很简单。我们只需要找到一个长度为奇数的前缀,使其变成全 \(0\)​ 即可套用奇数的情况

说实话我觉得这道题有那么点构造的感觉,实际上手玩玩就会发现这些性质,只是可能没想到怎么做罢了

时间复杂度 \(\mathcal{O}(n)\)

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
void up(int &x,int y) { x < y ? x = y : 0; }
void down(int &x,int y) { x > y ? x = y : 0; }
#define N ((int)(2e5 + 15))

int n, a[N], b[N];
void solve()
{
    cin >> n;
    for(int i = 1; i <= n; i++) { cin >> a[i], a[i] ^= a[i - 1]; }
    if(a[n]) { cout << "NO" << '\n'; return; }
    if(n & 1)
    {
        int now = 0, tot = 0;
        while(now < n - 3) b[++tot] = now + 1, now += 2;
        while(now >= 0) b[++tot] = now + 1, now -= 2;
        cout << "YES\n" << tot << '\n';
        for(int i = 1; i <= tot; i++) cout << b[i] << " \n"[i == tot];
        return; 
    }
    for(int k = 1; k <= n; k += 2) if(!a[k])
    {
        int now = 0, tot = 0;
        if(k != 1) {
            while(now < k - 3) b[++tot] = now + 1, now += 2;
            while(now >= 0) b[++tot] = now + 1, now -= 2;
        }  
        now = k;
        if(k + 1 != n) {
            while(now < n - 3)  b[++tot] = now + 1, now += 2;
            while(now >= k) b[++tot] = now + 1, now -= 2;
        }
        cout << "YES\n" << tot << '\n';
        for(int i = 1; i <= tot; i++) cout << b[i] << " \n"[i == tot];
        return;
    }
    cout << "NO" << '\n';
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    int qwq; cin >> qwq; while(qwq--) solve();
    return 0;
}

参考文献

[1] https://www.luogu.com.cn/article/6c8rr6ql

[2] https://www.luogu.com.cn/article/afj6tai5


文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录