【JSOI2017】 预言(广义常系数齐次线性递推)

https://gmoj.net/senior/#main/show/100013

考虑\(m\le 100\)的部分分,不难想到矩阵乘法。

这里,把\(and\)定义乘法,\(xor\)定义为加法,然后做正常的矩阵乘法。

发现这个东西和常系数齐次线性递推很像。

常系数齐次线性递推是\(Mod\)一个多项式\(M\),这里我们也可以定义这么一个类似的多项式。

虽然\(and\)乘法没有逆运算,但是注意到每次除的都是\(M\)最高项,最高项系数\(=2^{32}-1\),任何一个数除以这个数得到自己,那么就没有问题了。

时间复杂度:\(O(n^2~log~m)\)

Code:

#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
#define ff(i, x, y) for(int i = x, _b = y; i <  _b; i ++)
#define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
using namespace std;

const int N = 2e3 + 5;

#define ui unsigned int

int n; ll m;
ui a[N], b[N];

const ui inf = 4294967295ll;

void qmo(ui *a) {
	fd(i, 2 * n, n + 1) if(a[i]) {
		fo(j, 1, n) a[i - j] ^= b[j] & a[i];
		a[i] = 0;
	}
}
ui c[N];
void mul(ui *a, ui *b) {
	fo(i, 0, 2 * n) c[i] = 0;
	fo(i, 0, n) fo(j, 0, n) c[i + j] ^= a[i] & b[j];
	qmo(c);
	fo(i, 0, n) a[i] = c[i];
}

ui s[N], x[N];

int main() {
	freopen("prophecy.in", "r", stdin);
	freopen("prophecy.out", "w", stdout);
	scanf("%d", &n);
	fo(i, 1, n) scanf("%u", &a[i]);
	fo(i, 1, n) scanf("%u", &b[i]);
	scanf("%lld", &m);
	s[0] = inf; x[1] = inf;
	for(; m; m /= 2, mul(x, x))
		if(m & 1) mul(s, x);
	ui ans = 0;
	fo(i, 1, n) ans ^= s[i] & a[i];
	pp("%u\n", ans);
}

posted @ 2020-04-21 11:46  Cold_Chair  阅读(216)  评论(0编辑  收藏  举报