遊戲 - 博弈論
阿新 • • 發佈:2018-11-11
題目大意:
給你一張DAG,每個點有個係數k[x],多次詢問,每次詢問給你每個點的點權。
兩個人輪流操作,每次操作形如選擇一個點權大於0並且有出邊的點x,使其點權val[x]–,並在其出邊中選擇恰好k[x]個點(可以重複)點權++。不能操作者輸,問先手是否必勝。記所有點出度的最大值是v。
。
題解:
考慮k=1怎麼做,發現就是個樸素的DAG上的遊戲。k>1和k=1類似,只不過後繼狀態變多了,並且後繼狀態是一堆狀態的並而已。
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define ull unsigned lint
#define db long double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define gc getchar()
#define N 110
#define S (1<<18)
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
inline int inn()
{
int x,ch;while((ch=gc)<'0'||ch>'9');
x=ch^'0';while((ch=gc)>='0'&&ch<='9')
x=(x<<1)+(x<<3)+(ch^'0');return x;
}
int v[S],vis[S],sz[S],lb[S],id[S],d[N],lst[N],ls[S];
vector<int> g[N];queue<int> q;int sg[N],k[N];
inline int toposort(int n)
{
memset(d,0,sizeof(int)*(n+1));
rep(x,1,n) Rep(i,g[x]) d[g[x][i]]++;
while(!q.empty()) q.pop();int t=0;
rep(i,1,n) if(!d[i]) q.push(i);
while(!q.empty())
{
int x=q.front();q.pop(),lst[++t]=x;
Rep(i,g[x]) if(!(--d[g[x][i]])) q.push(g[x][i]);
}
return 0;
}
inline int ok(int c,int k) { if(c>k) return 0;return ((c-k)&1)==0; }
inline int getsg(int n)
{
for(int t=n;t;t--)
{
int x=lst[t],all=(1<<((int)g[x].size()))-1,p=0;
if((int)g[x].size()==0) { sg[x]=0;continue; }
Rep(i,g[x]) id[1<<i]=g[x][i];v[0]=0;
rep(s,1,all) v[s]=v[s^lb[s]]^sg[id[lb[s]]];
rep(s,0,all) if(ok(sz[s],k[x])) vis[ls[++p]=v[s]]=1;
for(sg[x]=0;vis[sg[x]];sg[x]++);for(;p;vis[ls[p--]]=0);
// debug(x)sp,debug(sg[x])ln;
}
return 0;
}
int main()
{
int all=(1<<17)-1;
rep(i,1,all) lb[i]=(i&-i),sz[i]=sz[i^lb[i]]+1;
for(int T=inn(),curT=1,u,v;curT<=T;printf("\n"),curT++)
{
int n=inn(),m=inn();rep(i,1,n) g[i].clear();
rep(i,1,m) u=inn()+1,v=inn()+1,g[u].pb(v);
rep(i,1,n) k[i]=inn();toposort(n),getsg(n);
printf("Game#%d:\n",curT);
for(int curQ=1,Q=inn();curQ<=Q;curQ++)
{
int ans=0;printf("Round#%d: ",curQ);
rep(i,1,n) ans^=sg[i]*(inn()&1);
printf(ans?"WINNING\n":"LOSING\n");
}
}
return 0;
}