P11008 『STA - R7』异或生成序列 题解

提示:这是一篇不是正解的题解。

题目大意很明确,这里不再重述。

思路:

让我们充分发扬人类智慧(

根据异或运算的基本性质,若两个数同时异或会被消掉,比如 axorbxorb=a

观察题目,容易发现将 b 数列异或起来会有很多重复的数,而它们都能消掉。

即:

b1xorb2xorxorbi1=p1xorpi(i[2,n])

再根据异或运算的另一个性质:若 axorb=c,则 a=bxorc,得:

pi=b1xorb2xorxorbi1xorp1(i[2,n])

也就是说,我们只要知道了一个 p1,再依次计算就能得到原数列。

我们先维护一个异或的类似前缀和的数组 sum,即 sumi 表示数列 b 的前 i 个数 xor 起来得到的结果,然后钦定一个 p1 并判断是否合法即可。

但这样的做法是 O(n2) 的,考虑优化。

发现瓶颈在于找合法 p1 的过程,如果能提前否掉一些不合法的选择就好了。

由于原数列是一个 1n 的排列,所以不能出现 0,换句话说就是 sumi1xorp1 不能为 0,即 p1sumi1。同时也不能大于 n,和上面如出一辙。

所以开一个桶提前标记 p1 不能取的值,剪掉一些情况。

Code:

#include <cmath>
#include <ctime>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 2000010;

int T, n;
int a[N], sum[N];
int ans[N];
int cnt;
bool st[N];

int main() {
    scanf("%d", &T);
    while(T--) {
        scanf("%d", &n);
        for(int i = 1; i < n; i++) {
            scanf("%d", &a[i]);
            sum[i] = sum[i - 1] ^ a[i];
            st[sum[i]] = true; //标记不能取的值
        }
        for(int p1 = 1; p1 <= n; p1++) {
            if(st[p1]) continue; //玄学剪枝
            ans[1] = p1;
            bool flag = true;
            for(int j = 2; j <= n; j++) {
                int tmp = sum[j - 1] ^ p1;
                if(tmp > n) {
                    flag = false;
                    break;
                }
                ans[j] = tmp;
            }
            if(flag) {
                for(int j = 1; j <= n; j++)
                    printf("%d ", ans[j]);
                puts("");
                break;
            }
        }
        for(int i = 1; i < n; i++) st[sum[i]] = false; //记得最后还原
    }
    return 0;
}

这里我才刚把不等于 0 的情况判掉就通过了。(加强数据迫在眉睫)

欢迎大佬给出详细的时间复杂度的证明或 hack。

posted @   Brilliant11001  阅读(17)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示