bzoj 2162: 男生女生

二分图最大团=补图最大独立集,因为这道题是人数多为第一关键字,男生多为第二关键字,所以男生的权值设为n+2,女生设为n+1
连边
S->x flow=n+2
x->y+n(xy之间没有边) flow=inf
x+n->T flow=n+1
然后总人数是ans/(n+1),男生是ans%(n+1)
发现任选一种,图都是一样的,A个男生向B个女生的每个都有边。
容斥,另<i,j>表示i个男生j个女生组成的子图选k个边的方案数=C(A,i)*C(B,j)*C(i*j,k)
答案是<A,B>-<A-1,B>-<A,B-1>+<A-2,B>+<A-1,B-1>+<A,B-2>……
    
    
    
    
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define ll long long
#define inf 1e9
#define eps 1e-8
#define md 19921228
#define N 110
using namespace std;
struct yts { int x,t,f,ne;} e[6010];
int v[N],dep[N],q[N];
int C[2510][2510];
bool a[55][55];
int S,T,num=1,ans=0;
void put(int x,int y,int f)
{
num++; e[num].x=x; e[num].t=y; e[num].f=f;
e[num].ne=v[x]; v[x]=num;
}
void add(int x,int y,int f)
{
put(x,y,f); put(y,x,0);
}
bool bfs()
{
memset(dep,0,sizeof(dep));
int h=0,w=1; q[1]=S; dep[S]=1;
while (h!=w)
{
int x=q[++h];
for (int i=v[x];i;i=e[i].ne)
{
int y=e[i].t;
if (!dep[y]&&e[i].f)
{
dep[y]=dep[x]+1;
q[++w]=y;
}
}
}
return dep[T]>0;
}
int dfs(int x,int flow)
{
if (x==T) return flow;
int now=0,used=0;
for (int i=v[x];i;i=e[i].ne)
{
int y=e[i].t;
if (e[i].f&&dep[y]==dep[x]+1)
{
now=dfs(y,min(flow-used,e[i].f));
e[i].f-=now; e[i^1].f+=now;
used+=now; if (used==flow) break;
}
}
if (!used) dep[x]=-1;
return used;
}
void dinic()
{
while (bfs()) ans+=dfs(S,inf);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin); freopen("a.out","w",stdout);
#endif
int n,m,k;
scanf("%d%d",&n,&k);
S=2*n+1,T=2*n+2;
for (int i=1;i<=n;i++) { add(S,i,n+2); add(i+n,T,n+1);}
scanf("%d",&m);
for (int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
a[x][y]=1;
}
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
if (!a[i][j]) add(i,j+n,inf);
dinic(); ans=n*(2*n+3)-ans;
int A=ans%(n+1),B=ans/(n+1)-A,mxn=A*B;
C[0][0]=1;
for (int i=1;i<=mxn;i++)
{
C[i][0]=1;
for (int j=1;j<=i;j++)
{
C[i][j]=C[i-1][j-1]+C[i-1][j];
if (C[i][j]>=md) C[i][j]-=md;
}
}
ll sum=0;
for (int i=0;i<=A;i++)
for (int j=0;j<=B;j++)
{
if (((i^j)&1)==((A^B)&1)) sum=(sum+1ll*C[i*j][k]*C[A][i]%md*C[B][j])%md;
else sum=(sum-1ll*C[i*j][k]*C[A][i]%md*C[B][j]%md+md)%md;
}
printf("%d %d\n%lld\n",A,B,sum);
return 0;
}

你可能感兴趣的:(bzoj 2162: 男生女生)