首页 > 其他分享 >[ARC084F] XorShift

[ARC084F] XorShift

时间:2024-11-06 14:57:21浏览次数:1  
标签:XorShift int lim vis ARC084F ans 线性 bit

模拟赛题。

考虑操作的构成,先忽略 \(1\) 操作,只考虑任意两个数的异或,不难发现所有能构成的数即为线性基。

再考虑 \(1\) 操作,显然可以对开始的每个数率先进行 \(1\) 操作再构建线性基。

记 \(lim = \max (\log_2 a, \log_2 m)\),发现所有可能有效的数都不超过 \(2^{2lim}\)。

再考虑构建出线性基后如何求答案,从高位到低位考虑,设考虑到第 \(i\) 位,且前面的位都达到了 \(m\) 的上界,转移分类讨论该位置是否选择即可。

容易发现上面所有操作都能用 bitset 优化。

复杂度瓶颈在于构建线性基,朴素实现是 \(O(\frac{lim^3}{w})\) 的,很遗憾是跑不过的,注意这里会进行 \(lim^2\) 次异或,原因是单个数的 \(1\) 个数最大为 \(lim\),而进行 \(lim\) 次 \(1\) 操作每次需要重新插入。

对于重复插入同一个串多次使用 \(1\) 操作的情况,可以不用每次插入 \(a \times 2^k\),而是将 \(a\) 在线性基中异或完的结果插入,根据线性基的性质正确性得到保证,而 \(1\) 的个数总共为 \(lim\) 个,所以复杂度变为 \(O(\frac{lim^2}{w})\)。

考场忘了加取址符,曹操了。

code
const int mod = 998244353;
const int N = 8005;
#define bit bitset <N>
int n, lim;
void read_bit(bit &x) {
	string s;
	cin >> s;
	reverse(all(s));
	for (int i = 0; i < (int)s.length(); i++) x[i] = (s[i] - '0' ? 1 : 0);
}
int getlg(bit &x) {
	if (!x.count()) return -1;
	for (int i = N - 1; ;i--) if (x[i]) return i;
	myassert(0);
}
bit m, a[10];
bit p[N], vis;
void ins(bit &x) {
	for (int i = lim + 1; i >= 0; i--) {
		if (!x[i]) continue;
		if (!vis[i]) {p[i] = x, vis[i] = 1; break;}
		x ^= p[i];
	}
}
int cnt[N], pw[N];

void main01() {
	ios::sync_with_stdio(0), cin.tie(0);
	read(n);
	read_bit(m);
	for (int i = 0; i < n; i++) read_bit(a[i]);
	if (!m.count()) {
		cout << 1 << '\n';
		return ;
	}
	lim = 0;
	for (int i = 0; i < n; i++) ckmax(lim, getlg(a[i]));
	lim += getlg(m);
	for (int i = 0; i < n; i++) {
		for (int c = getlg(a[i]); c <= lim + 1; c++, a[i] <<= 1) ins(a[i]);
	}
	int mxlen = getlg(m);
	for (int i = 0; i <= mxlen; i++) cnt[i] = (i ? cnt[i - 1] : 0) + vis[i];
	pw[0] = 1;
	for (int i = 1; i <= mxlen + 1; i++) pw[i] = 1ll * pw[i - 1] * 2 % mod;
	bit now; now.reset();
	int ans = 0, op = 0;
	for (int i = mxlen; i >= 0; i--) {
		if (m[i]) {
			if (now[i]) {
				if (!vis[i]) continue;
				ans += (i ? pw[cnt[i - 1]] : 1);
				ans %= mod;				
			} else {
				ans += (i ? pw[cnt[i - 1]] : 1);
				ans %= mod;
				if (!vis[i]) {op = 1; break;}
				now ^= p[i];				
			}
		} else {
			if (now[i]) {
				if (!vis[i]) {op = 1; break;}
				now ^= p[i];
			}
		}
	}
	if (!op) (ans += 1) %= mod;
	cout << ans << '\n';
}

标签:XorShift,int,lim,vis,ARC084F,ans,线性,bit
From: https://www.cnblogs.com/Anonymely/p/18530238

相关文章

  • xorshift 论文解析
    论文地址//xorshiftpaper:https://www.jstatsoft.org/article/view/v008i14/xorshift.pdf1.介绍.方法:把一个数跟他自己shift之后的数做异或.重复几次得到的数就是一个随机数.用c语言来说就是y^(y<<a)ory^(y>>a)2.理论:数学上RNG算法可以写作.我们给一个种子集合Z......
  • CF1743E FTL(哈希,DP)——关于 xorshift 的哈希冲突
    CF1743EFTL有两把laser枪,一把伤害\(p_0\)两发间隔时间至少\(t_0\),另一把\(p_1,t_1\)。打敌方太空船,血量\(N\)防御值\(s\),如果某个时刻你对太空船打出\(P\)的......