Luogu P5652 基础博弈练习题 (博弈论、图论)
生活随笔
收集整理的這篇文章主要介紹了
Luogu P5652 基础博弈练习题 (博弈论、图论)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題目鏈接
https://www.luogu.org/problem/P5652
題解
好題,想了四小時……
首先考慮如何判斷勝負:
首先假設只有一個柱子,那就是奇敗偶勝。不難發現最后一個奇數后面的偶數不影響結局,考慮最后一個奇數,它前面連續至少\(m\)個柱子都是必勝的。從它前面第\((m+1)\)個柱子開始,如果跳只能跳到必勝態,因此誰先跳誰輸,那么就是奇敗偶勝。
因此算法就是: 從最后一個奇數開始往前掃,每次跳到它前面距離它不小于\((m+1)\)且最近的奇數,經過的狀態是必敗態,其余都是必勝。最后如果能跳到左端點就是必敗,否則必勝。
考慮如何維護: 顯然把每個奇數和前面距離它不小于\((m+1)\)且最近的奇數連邊,構成了一個森林。問題等價于判斷一個點是否是另一個點的祖先。
RMQ-LCA親測會TLE,其實很簡單,直接按照DFS序判斷即可。
時間復雜度\(O(n+q)\).
代碼
#include<bits/stdc++.h> #define uint unsigned int #define llong long long using namespace std;inline int read() {int x=0; bool f=1; char c=getchar();for(;!isdigit(c);c=getchar()) if(c=='-') f=0;for(; isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+(c^'0');if(f) return x;return -x; }const int N = 1e6; struct Edge {int v,nxt; } e[(N<<1)+3]; int fe[N+3]; int fa[N+3]; int sz[N+3]; int a[N+3],prv[N+3]; int dfn[N+3]; int n,m,q,typ,en,cnt; llong aa,ab,ac,ap;inline int rnd() {return aa=(aa*ab+ac)%ap;}void addedge(int u,int v) {en++; e[en].v = v;e[en].nxt = fe[u]; fe[u] = en; } void dfs(int u) {dfn[u] = ++cnt; sz[u] = 1;for(int i=fe[u]; i; i=e[i].nxt){int v = e[i].v;if(v==fa[u]) continue;fa[v] = u;dfs(v);sz[u] += sz[v];} }int solve(int l,int r) {if(!(a[l]&1)) return 1;r = prv[r]; if(dfn[r]>=dfn[l]&&dfn[r]<=dfn[l]+sz[l]-1) {return 0;}return 1; }int main() {scanf("%d%d%d%d",&n,&m,&q,&typ);for(int i=1; i<=n; i++) {a[i] = read(),prv[i] = a[i]&1?i:prv[i-1]; if(a[i]&1) {int tmp = i-m-1>0?prv[i-m-1]:0; addedge(tmp,i); addedge(i,tmp);}}dfs(0);if(typ==0){uint fans = 0llu;for(int i=1; i<=q; i++){int l = read(),r = read();fans += solve(l,r)*i*i;}printf("%u\n",fans);}else{scanf("%lld%lld%lld%lld",&aa,&ab,&ac,&ap);uint fans = 0llu;for(int i=1; i<=q; i++){int l = rnd()%n+1,r = rnd()%n+1; if(l>r) swap(l,r);fans += solve(l,r)*i*i;}printf("%u\n",fans);}return 0; }總結
以上是生活随笔為你收集整理的Luogu P5652 基础博弈练习题 (博弈论、图论)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【学习笔记】OI模板整理
- 下一篇: CSP-S2019游记