【CodeChef】Strange Transform

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_39972971/article/details/83713724

【题目链接】

【思路要点】

  • 若我们将每一位分开考虑,异或可以看做模 22 意义下的加法。
  • 因此,一个位置 fk,xf_{k,x} 的值可以看做从 (k,x)(k,x) 出发,每次可以选择从 (x,y)(x,y) 走到 (x1,y),(x,y+1)(x-1,y),(x,y+1) ,最终停在 (0,x) (f0,x=1)(0,x)\ (f_{0,x}=1) 处的方案数对 22 取模。
  • 因此, fk1,xi=0k1k2fk2,x+i(k1k2i) (Mod 2)f_{k_1,x}\equiv\sum_{i=0}^{k_1-k_2}f_{k_2,x+i}*\binom{k_1-k_2}{i}\ (Mod \ 2)
  • 注意到由 LucasLucas 定理,当且仅当 aa 在二进制下数位包含 bb(ab)%2=1\binom{a}{b}\%2=1 ,上式有特殊情况: fk,xfk2i,x+fk2i,x+2i (Mod 2)f_{k,x}\equiv f_{k-2^i,x}+f_{k-2^i,x+2^i}\ (Mod \ 2)
  • 现在我们来考虑一个询问 (k,x)(k,x) ,由上面的推断,我们令 k=k&(2181)k=k\&(2^{18}-1) 不会使答案发生变化,下令 k=O(N)k=O(N)
  • kO(N)k≤O(\sqrt{N}) ,我们可以预处理出 fk,f_{k,*} 的结果,直接查询。
  • k>O(N)k>O(\sqrt{N}) ,令 bitbit 表示 kk 最高的为 11 的位置,则有 fk,x=fk2bit,xfk2bit,x+2bitf_{k,x}=f_{k-2^{bit},x}\oplus f_{k-2^{bit},x+2^{bit}} ,递归求解即可。
  • 时间复杂度 O(NN+QN)O(N\sqrt{N}+Q\sqrt{N})

【代码】

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
const int MAXM = 512;
const int goal = 511;
const int Min = 262143;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
template <typename T> void write(T x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
	write(x);
	puts("");
}
int n, m, type;
int a[MAXM][MAXN];
int work(int pos, int k) {
	if (k == 0) return a[type][pos];
	int tmp = k & -k, ans = 0;
	ans ^= work(pos, k ^ tmp);
	if (pos + tmp <= n) ans ^= work(pos + tmp, k ^ tmp);
	return ans;
}
int main() {
	read(n), read(m);
	for (int i = 1; i <= n; i++)
		read(a[0][i]);
	for (int i = 1; i <= goal; i++)
	for (int j = 1; j <= n; j++)
		a[i][j] = a[i - 1][j] ^ a[i - 1][j + 1];
	for (int i = 1; i <= m; i++) {
		int k, x;
		read(k), read(x);
		k &= Min, type = k & goal;
		writeln(work(x, k ^ type));
	}
	return 0;
}

没有更多推荐了,返回首页

私密
私密原因:
请选择设置私密原因
  • 广告
  • 抄袭
  • 版权
  • 政治
  • 色情
  • 无意义
  • 其他
其他原因:
120
出错啦
系统繁忙,请稍后再试

关闭