啊啊啊noi同步赛弃疗来刷水题了不知道会不会被老师打死
。。。
曾经用几行贪心水过vijos和luogu的题。。终于跪在了bzoj面前
显然答案具有单调性,考虑二分(暴力枚举也可以)
考虑对答案x的可行性验证:
对于每一个人拆成两个点,p,p'
p表示连向喜欢的,p'则是不喜欢的
那么对于喜欢的两个人连p,否则连p'
然后考虑k的限制,我们在同一个人的p和p'间连k的边
然后,S向男生连流量x的边,女生向t连流量x的边
然后跑dinic
如果满流,说明答案可行
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <queue>
#include <string>
#include <map>
#include <cstring>
#include <ctime>
#include <vector>
#define inf 1e9
#define ll long long
#define maxm 500010
#define maxn 1001
#define For(i,j,k) for(int i=j;i<=k;i++)
#define Dow(i,j,k) for(int i=k;i>=j;i--)
using namespace std;
inline ll read(){ ll x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; }
inline void write(ll x){ if (x<0) putchar('-'),x=-x; if (x>=10) write(x/10); putchar(x%10+'0'); }
inline void writeln(ll x){write(x);puts("");}
int dis[2001],q[2001],S,T,n,like[201][201],poi[200001],nxt[200001],v[200001],head[20001],ANS;
int k,ans,cnt;
char s[201];
inline void add(int x,int y,int z){poi[++cnt]=y;nxt[cnt]=head[x];v[cnt]=z;head[x]=cnt;poi[++cnt]=x;nxt[cnt]=head[y];v[cnt]=0;head[y]=cnt;}
inline bool bfs()
{
For(i,1,T) dis[i]=0;
int l=1,r=1;
q[1]=S;dis[S]=1;
while(l<=r)
{
for(int i=head[q[l]];i;i=nxt[i])
if(!dis[poi[i]]&&v[i]) dis[poi[i]]=dis[q[l]]+1,q[++r]=poi[i];
l++;
}
return dis[T]!=0;
}
inline int dfs(int x,int flow)
{
if(x==T) return flow;
int used=0;
for(int i=head[x];i;i=nxt[i])
{
if(v[i]&&dis[poi[i]]==dis[x]+1)
{
int mi=min(v[i],flow-used);
int tmp=dfs(poi[i],mi);
v[i]-=tmp;v[i^1]+=tmp;used+=tmp;
if(used==flow) return flow;
}
}
return used;
}
inline void dinic(){while(bfs()) ans+=dfs(S,inf);}
inline bool check(int x)
{
S=4*n+1;T=S+1;
cnt=1;
For(i,1,T) head[i]=0;
For(i,1,n)
For(j,1,n)
{
if(like[i][j]) add(i,j+3*n,1);
else add(i+n,j+2*n,1);
}
For(i,1,n) add(i,i+n,k),add(i+2*n,i+3*n,k);
For(i,1,n) add(S,i,x),add(3*n+i,T,x);
ans=0;dinic();
if(ans==x*n) return 1;else return 0;
}
int main()
{
n=read();k=read();
For(i,1,n)
{
scanf("\n%s",s+1);
For(j,1,n)
if(s[j]=='Y') like[i][j]=1;
}
int l=1,r=n;
while(l<=r)
{
int mid=(l+r)>>1;
if(check(mid)) ANS=max(ANS,mid),l=mid+1;else r=mid-1;
}
writeln(ANS);
}