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;
}


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