Codechef :A Game of Thrones/GTHRONES(网络流)

传送门

题解:
用Miller-Rabin建边,之后就是个二分图博弈。

这个直接判断最大匹配的必备点即可,注意每个点可以匹配多次,可以用网络流退流来判断。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;

const int RLEN=1<<18|1;
inline char nc() {
	static char ibuf[RLEN],*ib,*ob;
	(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
	return (ib==ob) ? -1 : *ib++;
}
template <typename T> inline void rd(T &x) {
	char ch=nc(); T i=0,f=1;
	while(!isdigit(ch)) {if(ch=='-') f=-1; ch=nc();}
	while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
	x=i*f;
}

const int N=1e5+50, M=2e6+50, inf=0x3f3f3f3f;
const int pr[]={2,3,5,7,11,13,17,19};
int n,b[N],col[N],vis[N],tar[N],win[N]; LL a[N];
vector <int> e[N];
inline LL mul(LL a,LL b,LL mod) {return (a*b-(LL)((long double)a/mod*b+1e-4)*mod+mod)%mod;}
inline LL power(LL a,LL b,LL mod,LL rs=1) {for(;b;b>>=1,a=mul(a,a,mod)) if(b&1) rs=mul(rs,a,mod); return rs;}
namespace mcmf {
	int g[N],nt[M],vt[M],c[M],ec=1;
	int lev[N],cur[N],q[N],src,des;
	inline void add(int x,int y,int cc) {
		nt[++ec]=g[x]; g[x]=ec; vt[ec]=y; c[ec]=cc;
		nt[++ec]=g[y]; g[y]=ec; vt[ec]=x; c[ec]=0;
	}
	inline bool bfs() {
		for(int i=1;i<=des;i++) lev[i]=0;
		int r; q[r=1]=src; lev[src]=1;
		for(int i=1;i<=r;i++) {
			int u=q[i];
			for(int e=g[u];e;e=nt[e]) if(c[e] && (!lev[vt[e]])) {
				lev[vt[e]]=lev[u]+1; q[++r]=vt[e];
				if(vt[e]==des) return true;
			}
		} return false;
	}
	inline int dinic(int x,int f) {
		if(x==des) return f;
		int rs=0;
		for(int &e=cur[x];e;e=nt[e]) {
			if(!c[e] || (lev[vt[e]]!=lev[x]+1)) continue;
			int o=dinic(vt[e],min(f-rs,c[e]));
			c[e]-=o; c[e^1]+=o; rs+=o;
			if(rs==f) return rs;
		} return lev[x]=0, rs;
	} 
	inline void maxflow() {
		while(bfs()) {
			int rs; memcpy(cur+1,g+1,sizeof(int)*des);
			while((rs=dinic(src,inf))) memcpy(cur+1,g+1,sizeof(int)*des);
		}
	}
}

inline void dfs(int x,int c) {
	col[x]=c; vis[x]=1;
	for(auto v:e[x]) if(!vis[v]) dfs(v,c^1);
}

inline bool MR(LL t) {
	if(t==1) return false;
	if(t<=3) return true;
	if((t%6)!=1 && (t%6)!=5) return false;
	LL s1=0, s2=t-1;
	while(!(s2&1)) s1++, s2>>=1;
	for(int i=0;i<=7;i++) {
		if(t==pr[i]) return true;
		LL v=power(pr[i],s2,t);
		for(int j=1;v!=1 && j<=s1;j++) {
			LL v2=mul(v,v,t);
			if(v2==1 && (v!=1 && v!=t-1)) return false;
			v=v2;
		}
		if(v!=1) return false;
	} return true;
}
inline bool check(LL a,LL b) {
	if(a<b) swap(a,b);
	if(a%b) return false;
	return MR(a/b);
}
int main() {
	rd(n);
	for(int i=1;i<=n;i++) rd(a[i]), rd(b[i]);
	mcmf::src=n+1; mcmf::des=n+2;
	
	for(int i=1;i<=n;i++) 
		for(int j=i+1;j<=n;j++)
			if(check(a[i],a[j])) 
				e[i].push_back(j), e[j].push_back(i);
	for(int i=1;i<=n;i++) if(!vis[i]) dfs(i,0);
	
	for(int i=1;i<=n;i++) for(auto v:e[i]) if(i<v) 
		if(col[i]) mcmf::add(v,i,inf);
		else mcmf::add(i,v,inf); 
		
	for(int i=1;i<=n;i++) 
		if(col[i]) mcmf::add(i,mcmf::des,b[i]), tar[i]=mcmf::ec-1;
		else mcmf::add(mcmf::src,i,b[i]), tar[i]=mcmf::ec-1;
		
	mcmf::maxflow();
	
	for(int i=1;i<=n;i++) if(!mcmf::c[tar[i]]) {
		static int q[N],r; r=0;
		for(int e=mcmf::g[i];e;e=mcmf::nt[e]) {
			int v=mcmf::vt[e];
			if(v<=n && mcmf::c[e|1]) q[++r]=tar[v];
		}
		for(int j=1;j<=r;j++) ++mcmf::c[q[j]];
		if(!mcmf::bfs()) win[i]=1;
		for(int j=1;j<=r;j++) --mcmf::c[q[j]];
	}
	
	LL ans=2e18;
	for(int i=1;i<=n;i++) if(!win[i]) ans=min(ans,a[i]);
	if(ans!=2e18) printf("Bran %lld\n",ans);
	else puts("Tyrion");
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值