给一把锁,有一些数字被试过了,最多五个数字,每次将一个数字转动1(0-9成环),然后尝试能不能打开,每个数字只能尝试一次,问先手还是后手必胜。
比赛的时候看了这个题,当时觉得不是计算sg函数的博弈,像是图论,模型转换也都比较对,但是根本没见过二分图博弈,实在想不出来,结束看是个很裸的二分图博弈。
可以看出每次仅转动一个数字,必然导致所有数字的和奇偶发生变化,所以所有的数字构成一个二分图,剩下就是一个裸的二分图博弈了,看了https://www.pianshen.com/article/14591177358/这篇博客,觉得写得很清楚了。之前完全没做过二分图博弈的题,据cjb说去年ICPC南昌网络赛有过二分图博弈,南昌是去年唯一一场写过总结也是打的最炸的一场网络赛,然而我一点印象没有,只记得那场卡一个数学和dijkstra半天???只需要跑一个二分图匹配就好了,HK或者dinic都能过,复杂度$nsqrt(n)$
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; typedef pair <ll,ll> pii; #define rep(i,x,y) for(int i=x;i<y;i++) #define rept(i,x,y) for(int i=x;i<=y;i++) #define per(i,x,y) for(int i=x;i>=y;i--) #define all(x) x.begin(),x.end() #define pb push_back #define fi first #define se second #define mes(a,b) memset(a,b,sizeof a) #define mp make_pair #define dd(x) cout<<#x<<"="<<x<<" " #define de(x) cout<<#x<<"="<<x<<" " #define debug() cout<<"I love Miyamizu Mitsuha forever. " const int inf=0x3f3f3f3f; const int N=400010,M=5000010; const int maxn=1e5+5; bool ban[maxn]; int way[maxn]; int head[N],ver[M],edge[M],Next[M],d[N]; int e[maxn]; int n,s,t,tot,maxflow; queue<int> q; vector<int> v[maxn]; void add(int x,int y,int z) { // dd(x);dd(y);de(z); ver[++tot]=y,edge[tot]=z,Next[tot]=head[x],head[x]=tot; ver[++tot]=x;edge[tot]=0,Next[tot]=head[y],head[y]=tot; } bool bfs() { mes(d,0); while(!q.empty()) q.pop(); q.push(s); d[s]=1; while(!q.empty()) { int x=q.front(); q.pop(); for(int i=head[x];i;i=Next[i]) if(edge[i]&&!d[ver[i]]) { q.push(ver[i]); d[ver[i]]=d[x]+1; if(ver[i]==t) return 1; } } return 0; } int dinic(int x,ll flow) { if(x==t) return flow; int rest=flow,k; for(int i=head[x];i&&rest;i=Next[i]) { if(edge[i]&&d[ver[i]]==d[x]+1) { k=dinic(ver[i],min(rest,edge[i])); if(!k) d[ver[i]]=0; edge[i]-=k; edge[i^1]+=k; rest-=k; } } return flow-rest; } int run(int l,int nn) { tot=1; s=nn,t=nn+1; rept(i,0,t) head[i]=0; rep(i,0,nn) { if(ban[i]) continue; if(way[i]) { e[i]=tot+1; add(i,t,1); continue; } e[i]=tot+1; add(s,i,1); rep(j,0,2*l) { if(ban[v[i][j]]||v[i][j]>=nn) continue; add(i,v[i][j],1); } } int flow=0; maxflow=0; while(bfs()) while(flow=dinic(s,inf)) maxflow+=flow; return maxflow; } void test() { int l,m,st; cin>>l>>m>>st; int nn=1; rep(i,0,l) nn*=10; rep(i,0,nn) ban[i]=0; rep(i,0,m) { int x; cin>>x; ban[x]=1; } int ans1=run(l,nn); if(edge[e[st]]) { cout<<"Bob "; return ; } ban[st]=1; int ans2=run(l,nn); if(ans1==ans2) cout<<"Bob "; else cout<<"Alice "; } int cal(int x) { int ans=0; while(x) { ans+=x%10; x/=10; } return ans%2; } void init() { int n=100000; rep(i,0,n) { way[i]=cal(i); int x=i,mul=1; rep(j,0,5) { if(x%10==0) v[i].pb(i+9*mul); else v[i].pb(i-mul); if(x%10==9) v[i].pb(i-9*mul); else v[i].pb(i+mul); mul*=10; x/=10; } } } int main() { ios::sync_with_stdio(false); cin.tie(0); init(); int q; cin>>q; while(q--) test(); return 0; }