題目大意:
YSGH和YGSH在打膈膜,YSGS在旁邊圍觀。
規則是這樣的,先給定一個正整數和一個個數序列,一開始有一個棋子在的第一個位置,並將減去。此後雙方輪流操作,每次操作,假設當前棋子在,可以把棋子移到一個位置,滿足且,然後將減,YSGH先手,誰先不能操作誰輸。
衆所周知,YSGH和YGSH都是絕頂聰明的,所以兩人都會使用最優策略。
而隔膜使用的序列是一個序列的一個連續非空子序列,當然序列和每次隔膜使用的序列都是YSGS定的。
現在他們進行了輪遊戲,給出每輪遊戲使用的區間,請你判斷每輪誰會贏
解題思路:
我們可以知道的是當爲奇數時先手必勝
那麼選這段中的一個時,先手必敗,因爲這一段裏面都可以轉移到,轉移到時先手和後手順序就換過來
那麼如果爲偶數那麼先手就必敗,而選這段中的一個時,先手必勝
我們維護一個,表示一個且爲奇數
那麼如果必勝,那麼也必勝
對於每一個,與連邊(其中爲父節點)
那麼我們就會構建出一個樹
若區間滿足爲的祖先那麼先手必敗, 否則先手必勝
用序判斷
#include<cstdio>
#include<algorithm>
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);
}