洛谷11月月賽 III Div.2 T3 基礎博弈練習題

題目大意:

YSGH和YGSH在打膈膜,YSGS在旁邊圍觀。

規則是這樣的,先給定一個正整數mm和一個nn個數序列BB,一開始有一個棋子在BB的第一個位置,並將B1B_1減去11。此後雙方輪流操作,每次操作,假設當前棋子在ii,可以把棋子移到一個位置jj,滿足j[i,min(i+m,n)]j\in[i,min(i+m,n)]Bj>0B_j>0,然後將BjB_j11,YSGH先手,誰先不能操作誰輸。

衆所周知,YSGH和YGSH都是絕頂聰明的,所以兩人都會使用最優策略。

而隔膜使用的序列BB是一個序列AA的一個連續非空子序列,當然序列AA和每次隔膜使用的序列BB都是YSGS定的。

現在他們進行了qq輪遊戲,給出每輪遊戲使用的區間,請你判斷每輪誰會贏

解題思路:

我們可以知道的是當aia_i爲奇數時先手必勝
那麼選[im,i1][i-m, i-1]這段中的一個時,先手必敗,因爲這一段裏面都可以轉移到ii,轉移到ii時先手和後手順序就換過來
那麼如果aia_i爲偶數那麼先手就必敗,而選[im,i1][i-m, i-1]這段中的一個時,先手必勝
我們維護一個nextinext_i,表示一個j<=ij<=iaja_j爲奇數
那麼如果ii必勝,那麼nextim1next_{i-m-1}也必勝
對於每一個i>m+1i>m+1,與nextim1next_{i-m-1}連邊(其中nextim1next_{i-m-1}爲父節點)
那麼我們就會構建出一個樹
若區間[l,r][l, r]滿足llnextinext_i的祖先那麼先手必敗, 否則先手必勝
dfsdfs序判斷

Accepted code:Accepted\ code:

#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);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章