COCI2017-2018#3 Dojave || 洛谷P4443

The biggest event of the year ended tragically for Croatian teams. The most influential theoretician of CERC of all time, the founder of the popular page CERC Tips, and in his free time an outstanding bass player, in his most recent performance failed to get his team to the finals.

In order to get over his existential troubles, our subject is spending time playing games of chance. He is especially interested in the following game:

You are given a positive integer M. Our protagonist sees in front of him a permutation of an array of numbers 0, 1, 2, ..., 2^M2M - 1.

The computer chooses a nonempty contiguous subsequence of the given permutation, which it then lights up over a capital city of one of the countries in Southeastern Europe.

Our confidant, after fighting off tears caused by memories of old times, must choose two distinct elements of the permutation and swap their places​. Our man of the hour wins if and only if the bitwise XOR of the numbers in the lit up subsequence after the substitution is precisely​ 2^M2M - 1.

Our hero wants to know the number of contiguous subsequences ​the computer can light up so that he can win.

Help our hero overcome his (id)entity crisis so our favourite page can be fully active again.

输入输出格式

输入格式:

The first line of input contains the integer M (1 ≤ M ≤ 20),

The following line contains 2^M2M space-separated numbers that make up a permutation of the array 0, 1, 2, ..., 2^M2M - 1.

输出格式:

You must output the total number of contiguous subsequences that a computer can light up so our hero can win.

输入输出样例

输入样例#1:  复制
2
0 1 2 3
输出样例#1:  复制
9
输入样例#2:  复制
3
3 7 0 4 6 1 5 2
输出样例#2:  复制
33
输入样例#3:  复制
4
13 0 15 12 4 8 7 3
11 14 6 10 1 5 9 2
输出样例#3:  复制
133

说明

In test cases worth 50% of total points, it will hold 1 ≤ M ≤ 14.

Clarification​ ​of​ ​the​ ​test​ ​cases:

In the first test case, if the computer chooses the subsequence [1 2 3], our hero can replace the numbers 0 and 3. In this case, he can actually win for every chosen contiguous subsequence, except the entire array.

In the second test case, if the computer chooses the entire array [3 7 0 4 6 1 5 2] as the lit up subsequence, our hero can’t change the XOR of the subsequence (which is 0), no matter which two elements are swapped.

https://www.luogu.org/problemnew/show/P4443

题目大意 ::

给定一个正整数M,和0到2M-1共2M个数的排列,计算机先选择一段连续的子串,你必须选两个不同的元素出来,交换它们的位置,使得计算机选出来的子串在交换后的元素的异或值为2M-1,如果可以,你将获胜。现在请你统计有多少种不同的选法,你可以获胜。

就是叫你求出所有满足条件的区间的个数。。。

官方标程是 线段树 + !@#¥%…… 我看不懂......(orz洛谷大佬写的线段树)......

线段树 :: 

//for test!
#include <bits/stdc++.h>
using namespace std;

#define ms(s, n) memset(s, n, sizeof(s))
#define FOR(i, a, b) for (int i = (a); i < (b); i++)
#define FORd(i, a, b) for (int i = (a) - 1; i >= (b); i--)
#define FORall(it, a) for (__typeof((a).begin()) it = (a).begin(); it != (a).end(); it++)
#define sz(a) int((a).size())
#define present(t, x) (t.find(x) != t.end())
#define all(a) (a).begin(), (a).end()
#define uni(a) (a).erase(unique(all(a)), (a).end())
#define pb push_back
#define pf push_front
#define mp make_pair
#define fi first
#define se second
#define prec(n) fixed<<setprecision(n)
#define bit(n, i) (((n) >> (i)) & 1)
#define bitcount(n) __builtin_popcountll(n)
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<int, int> pi;
typedef vector<int> vi;
typedef vector<pi> vii;
const int MOD = (int) 1e9 + 7;
const int FFTMOD = 1007681537;
const int INF = (int) 1e9;
const ll LINF = (ll) 1e18;
const ld PI = acos((ld) -1);
const ld EPS = 1e-9;
inline ll gcd(ll a, ll b) {ll r; while (b) {r = a % b; a = b; b = r;} return a;}
inline ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}
inline ll fpow(ll n, ll k, int p = MOD) {ll r = 1; for (; k; k >>= 1) {if (k & 1) r = r * n % p; n = n * n % p;} return r;}
template<class T> inline int chkmin(T& a, const T& val) {return val < a ? a = val, 1 : 0;}
template<class T> inline int chkmax(T& a, const T& val) {return a < val ? a = val, 1 : 0;}
inline ll isqrt(ll k) {ll r = sqrt(k) + 1; while (r * r > k) r--; return r;}
inline ll icbrt(ll k) {ll r = cbrt(k) + 1; while (r * r * r > k) r--; return r;}
inline void addmod(int& a, int val, int p = MOD) {if ((a = (a + val)) >= p) a -= p;}
inline void submod(int& a, int val, int p = MOD) {if ((a = (a - val)) < 0) a += p;}
inline int mult(int a, int b, int p = MOD) {return (ll) a * b % p;}
inline int inv(int a, int p = MOD) {return fpow(a, p - 2, p);}
inline int sign(ld x) {return x < -EPS ? -1 : x > +EPS;}
inline int sign(ld x, ld y) {return sign(x - y);}
#define db(x) cerr << #x << " = " << (x) << " ";
#define endln cerr << "\n";

const int maxn = 1 << 20;
int n;
int a[maxn];
int f[maxn];
long long dp[maxn][2];
int mn[maxn];
int mx[maxn];

int st[2][maxn << 1];
void updmn(int st[], int p, int val) {
    for (st[p += n] = val; p > 1; ) p >>= 1, st[p] = min(st[p << 1], st[p << 1 | 1]);
}
int querymn(int st[], int l, int r) {
    int res = INF;
    for (l += n, r += n + 1; l < r; l >>= 1, r >>= 1) {
        if (l & 1) chkmin(res, st[l++]);
        if (r & 1) chkmin(res, st[--r]);
    }
    return res;
}
void updmx(int st[], int p, int val) {
    for (st[p += n] = val; p > 1; ) p >>= 1, st[p] = max(st[p << 1], st[p << 1 | 1]);
}
int querymx(int st[], int l, int r) {
    int res = -INF;
    for (l += n, r += n + 1; l < r; l >>= 1, r >>= 1) {
        if (l & 1) chkmax(res, st[l++]);
        if (r & 1) chkmax(res, st[--r]);
    }
    return res;
}

void solve() {
    cin >> n; n = 1 << n;
    FOR(i, 0, n) mn[i] = INF, mx[i] = -INF;
    FOR(i, 0, n) {
        cin >> a[i];
        chkmin(a[i], a[i] ^ n - 1);
        chkmin(mn[a[i]], i);
        chkmax(mx[a[i]], i);
    }
    if (n == 2) {
        cout << 2 << "\n";
        return;
    }
    FOR(i, 0, n) {
        updmn(st[0], i, mn[a[i]]);
        updmx(st[1], i, mx[a[i]]);
    }
    long long res = 0;
    FOR(i, 0, n) {
        int k = a[i];
        if (mx[k] == i) {
            f[i] = -1;
            int j = querymn(st[0], mn[k], mx[k]);
            if (j >= mn[k]) {
                f[i] = j;
            }
            else {
                f[i] = f[mx[a[j]]];
            }
            if (f[i] != -1 && querymx(st[1], f[i], i) <= i) {
                int len = i - f[i] + 1;
                int par = len / 2 & 1;
                dp[i][par] = 1;
                if (f[i]) {
                    dp[i][par] += dp[f[i] - 1][0];
                    dp[i][par ^ 1] += dp[f[i] - 1][1];
                }
                res -= dp[i][0];
            }
        }
    }
    res += (long long) n * (n + 1) / 2;
    cout << res << "\n";
}

int main(int argc, char* argv[]) {
    ios_base::sync_with_stdio(0), cin.tie(0);
    if (argc > 1) {
        assert(freopen(argv[1], "r", stdin));
    }
    if (argc > 2) {
        assert(freopen(argv[2], "wb", stdout));
    }
    solve();
    return 0;
}//标程....

但是我只会写写被数据卡到飞起的hash......怎么办?一个hash不行就2个嘛......

hash :: 

//hash 有毒, 双hash才可过 ;  
#include <cstdio>
#include <map>
using namespace std;

typedef long long ll;
const int N = 1 << 20;
map<pair<ll, ll>, int> p[4];
int rand() { static int c = 703; return c = 1ll * c * 15315ll % 0x7fffffff; }
int n, a[N + 5], pos[N + 5], f1[N + 5], f2[N + 5], r1[N + 5], r2[N + 5];

int main() {
    scanf("%d", &n); int c = 1 << n; ll ans = 1ll * c * (c + 1) / 2ll;
    for( int i = 1; i <= c; i ++) scanf("%d", a + i), pos[a[i]] = i;
    
    for( int i = 0; i <= c / 2; i ++) r1[pos[i]] = r1[pos[i ^ (c-1)]] =  rand(), r2[pos[i]] = r2[pos[i ^ (c-1)]] = rand();
    
    for( int i = 1; i <= c; i ++) f1[i] = f1[i-1] ^ r1[i], f2[i] = f2[i-1] ^ r2[i];
    
    for( int i = 0; i <= c; i ++) ans -= p[i % 4][make_pair(f1[i], f2[i])], p[i % 4][make_pair(f1[i], f2[i])] ++;
    
    printf(n == 1 ? "2" : "%lld\n", ans); 
}

证明如下 ::

  设 k = (1 << M) - 1; pos[] 表示值为 x 的数的位置;

  首先考虑区间长度为奇数的时候, 设区间的xor值为A, 则将其中某个数换走后的xor值为A ^a[i], 那么要使区间xor值为k, 则需要换一个a[j] = k ^ A ^a[i](这不是废话么......), 设 g = k ^ A(这是个定值)

如果说这个区间内所有的数想要进行交换的数都在这个区间内, 则有 pos[g ^ a[1]] ∈ [l, r], pos[g ^ a[2]] ∈ [l, r]......,因为 a[i] != a[j], 所以g ^ a[i] != g ^a[j](又是废话),

所以g ^ a[1] ^ g ^ a[2] ^ .... g ^ a[n] = a[1] ^ a[2] ^ ...^a[n], 所以g ^ a[1] ^ a[2] ^ ... ^a[n] == a[1] ^ a[2] ^ ... ^ a[n], 所以当前情况g = 0。。。又 g = k ^ A,所以 k == A。 所以当区间长度为奇数时是绝对满足条件的

  好, 现在开始考虑区间长度为偶数时 先讨论 区间长度 / 2 为奇数时

    同样,如果为不合法区间,则有 a[i] ^ g = a[j], pos[a[i]] ∈ [l, r], pos[a[j]] ∈ [l, r]; 所以 g = a[i] ^a[j]; 所以最后区间的 xor 值为 g (自己想一想)。

    所以 A = a[i] ^ a[j]。 g = K ^ A = a[i] ^a[j]; k ^ a[i] ^ a[j] = a[i] ^a[j]。(好像在哪里见过。。。。)

  现在讨论区间长度为偶数且区间长度 / 2 为偶数的情况

    同上,区间的 xor 值为 0(不想解释了,反正上面看懂了也很简单),则有 g = K(g = k ^ A), 所以 a[i] ^a[j] = k (对于任意a[i]都只有一个a[j]与之配对,不想证明了), 所以到这里我们就把所有不合法区间的条件求出了。

  总结下,现在我们知道了区间的总数为 (k + 2) * (k + 1) / 2,区间长度为4的倍数且其中的数都是配♂对的数的区间不合法,减去,双hash乱搞ok(一个hash让我Wa到怀疑人生);

证明完毕。。。(我语文很差,可能有的地方表达有误。谁看懂标程的可以说下否?)

猜你喜欢

转载自www.cnblogs.com/miecoku/p/9020700.html