游戏 - 博弈论

题目大意:
给你一张DAG,每个点有个系数k[x],多次询问,每次询问给你每个点的点权。
两个人轮流操作,每次操作形如选择一个点权大于0并且有出边的点x,使其点权val[x]–,并在其出边中选择恰好k[x]个点(可以重复)点权++。不能操作者输,问先手是否必胜。记所有点出度的最大值是v。 n 100 , m 1700 , q 1000 , v 17 , T 20 n\le100,m\le1700,q\le1000,v\le17,T\le20
题解:
考虑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;
}

猜你喜欢

转载自blog.csdn.net/Mys_C_K/article/details/83058209