YSGH和YGSH在打膈膜,YSGS在旁边围观。
规则是这样的,先给定一个正整数 m m m和一个 n n n个数序列 B B B,一开始有一个棋子在 B B B的第一个位置,并将 B 1 B_1 B1减去 1 1 1。此后双方轮流操作,每次操作,假设当前棋子在 i i i,可以把棋子移到一个位置 j j j,满足 j ∈ [ i , m i n ( i + m , n ) ] j\in[i,min(i+m,n)] j∈[i,min(i+m,n)]且 B j > 0 B_j>0 Bj>0,然后将 B j B_j Bj减 1 1 1,YSGH先手,谁先不能操作谁输。
众所周知,YSGH和YGSH都是绝顶聪明的,所以两人都会使用最优策略。
而隔膜使用的序列 B B B是一个序列 A A A的一个连续非空子序列,当然序列 A A A和每次隔膜使用的序列 B B B都是YSGS定的。
现在他们进行了 q q q轮游戏,给出每轮游戏使用的区间,请你判断每轮谁会赢
我们可以知道的是当 a i a_i ai为奇数时先手必胜
那么选 [ i − m , i − 1 ] [i-m, i-1] [i−m,i−1]这段中的一个时,先手必败,因为这一段里面都可以转移到 i i i,转移到 i i i时先手和后手顺序就换过来
那么如果 a i a_i ai为偶数那么先手就必败,而选 [ i − m , i − 1 ] [i-m, i-1] [i−m,i−1]这段中的一个时,先手必胜
我们维护一个 n e x t i next_i nexti,表示一个 j < = i j<=i j<=i且 a j a_j aj为奇数
那么如果 i i i必胜,那么 n e x t i − m − 1 next_{i-m-1} nexti−m−1也必胜
对于每一个 i > m + 1 i>m+1 i>m+1,与 n e x t i − m − 1 next_{i-m-1} nexti−m−1连边(其中 n e x t i − m − 1 next_{i-m-1} nexti−m−1为父节点)
那么我们就会构建出一个树
若区间 [ l , r ] [l, r] [l,r]满足 l l l为 n e x t i next_i nexti的祖先那么先手必败, 否则先手必胜
用 d f s dfs dfs序判断
#include
#include
using namespace std;
const int N = 1000005;
const long long mod = 1ll<<32;
struct Line {
int to, next;
}e[N];
int n, m, q, l, r, A, B, C, P, cnt, type;
int a[N], dfn[N], last[N], next[N], size[N];
long long ans;
inline int rnd() {
return A = (A * B + C) % P;}
inline void add(int x, int y) {
e[++cnt] = (Line){
y, last[x]}; last[x] = cnt;
}
void dfs(int x) {
dfn[x] = ++cnt; size[x] = 1;
for (int i = last[x]; i; i = e[i].next)
dfs(e[i].to), size[x] += size[e[i].to];
return;
}
int main() {
scanf("%d %d %d %d", &n, &m, &q, &type);
for (int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
if (a[i] & 1) next[i] = i;
else next[i] = next[i-1];
if (i > m + 1) add(next[i-m-1], i);
else add(0, i);
}
dfs(0);
if (type) scanf("%d %d %d %d", &A, &B, &C, &P);
for (int i = 1; i <= q; ++i) {
if (type)
l = rnd() % n + 1, r = rnd() % n + 1;
else scanf("%d %d", &l, &r);
if (l > r) swap(l, r);
if (dfn[l] > dfn[next[r]] || dfn[l] + size[l] < dfn[next[r]] + size[next[r]])
(ans += (long long)i * i) %= mod;
}
printf("%lld\n", ans);
}