【CodeChef】Strange Transform

本文深入探讨了异或运算在动态规划中的应用,通过将异或视为模2加法,提出了一个高效算法解决特定问题。文章详细解释了如何通过递归和预处理策略,将复杂度降低至O(N√N+Q√N),并提供了完整代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【题目链接】

【思路要点】

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

【代码】

#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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值