BZOJ 3168: [Heoi2013]钙铁锌硒维生素

对着网上下的数据拍发现过不去,交上去就1A了。。。。。。

看discuss才发现标程是错的。。。。。。。

根据14年的论文,A为n维向量的一组基,B中任意行向量属于Span(A),于是可以得出系数矩阵C,且C*A=B,A中行向量x能被B中行向量y替换当且仅当y的表示向量(C中的一个列向量)中x位置的系数不为0,于是C的转置即为二分图的邻接矩阵,问题转化为二分图最小字典序最大匹配

首先跑一遍匈牙利搞出一个最大匹配来

对于每个S点贪心地判断T点能否与它匹配

条件为T的匹配点能够走出一条到达S的增广路

(即linked[T]-Ti-Si-Tj---------T-S,这个过程和匈牙利差不多)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
using namespace std;
#define rep(i,l,r) for(int i=l;i<=r;i++)
#define per(i,r,l) for(int i=r;i>=l;i--)
#define mmt(a,v) memset(a,v,sizeof(a))
const int N=300+5;
typedef long long ll;
const int p=999911657;
ll qmul(ll a,ll b){
	ll ans=1;
	for(;b;b>>=1,a=a*a%p)if(b&1)ans=ans*a%p;
	return ans;
}
ll inv(int x){return qmul(x,p-2);}
bool g[N][N];
int n;
struct matrix{
	int a[N][N];
	void clr(){mmt(a,0);}
	void init(){rep(i,1,n)rep(j,1,n)scanf("%d",&a[i][j]);}
	bool inverse(){
		int d;
		rep(k,1,n){
			if(!a[k][k])return false;
			d=inv(a[k][k]);
			rep(i,1,n)if(i!=k)a[k][i]=1LL*a[k][i]*(p-d)%p;
			rep(i,1,n)if(i!=k)a[i][k]=1LL*a[i][k]*d%p;
			rep(i,1,n)if(i!=k)rep(j,1,n)if(j!=k)
			(a[i][j]+=1LL*a[i][k]*a[k][j]%p*a[k][k]%p)%=p;
			a[k][k]=d;
		}
		return true;
	}
	matrix operator * (const matrix &b)const{
		static matrix c;c.clr();
		rep(i,1,n)rep(j,1,n)rep(k,1,n)
		(c.a[i][j]+=1LL*a[i][k]*b.a[k][j]%p)%=p;
		return c;
	}
	void print(){
		rep(i,1,n){
			rep(j,1,n)printf("%d ",a[i][j]);
			puts("");
		}
	}
}a,b,c;
void build(){rep(i,1,n)rep(j,1,n)g[i][j]=!!c.a[j][i];}
bool vis[N];
int linked[N];
bool match(int u){
	rep(v,1,n)if(g[u][v]&&!vis[v]){
		vis[v]=1;
		if(!linked[v]||match(linked[v])){
			linked[v]=u;
			return true;
		}
	}
	return false;
}
bool dfs(int u,int s){
	if(u==s)return true;
	rep(v,1,n)if(g[u][v]&&!vis[v]){
		vis[v]=1;
		if(dfs(linked[v],s)){
			//printf("%d %d\n",u,v);
			linked[v]=u;
			return true;
		}
	}
	return false;
}
int main(){
	//freopen("a.in","r",stdin);
	scanf("%d",&n);
	a.init();b.init();
	if(!a.inverse()){puts("NIE");return 0;}
	c=b*a;build();
	int ans=0;
	rep(i,1,n){mmt(vis,0);ans+=match(i);}
	if(ans!=n){puts("NIE");return 0;}
	puts("TAK");
	rep(i,1,n){
		mmt(vis,0);
		rep(j,1,n)g[i-1][j]=0;
		rep(j,1,n)if(g[i][j]&&!vis[j]){
			vis[j]=1;
			if(linked[j]>=i&&dfs(linked[j],i)){
				linked[j]=i;
				printf("%d\n",j);
				rep(k,1,n)g[k][j]=0;
				break;
			}
		}
	}
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章