ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

ABC 214 G,H 题解

2021-08-14 23:34:23  阅读:200  来源: 互联网

标签:214 ABC int 题解 dis heap now dp define


ABC 214 G,H 题解

G

考虑建一张图。

途中\(p_i,q_i\)之间有一条边。

则问题转化成,在每条边上写上两两不同的数字,使得每一条边写的数字和两端的数字不同。

考虑容斥。

钦定一些边,然后给边定向,使得每一个点的出度\(\leq 1\)。

可以发现构成的连通块是个环,直接破环为链dp。

然后对于所有环做一次卷积就是答案。

时间复杂度\(O(N^2\log N)\)。

code:

#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define LL long long
#define IT iterator
#define PB push_back
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a<b;++a)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
#define ALL(a) a.begin(),a.end()
#define POB pop_back
#define ff fflush(stdout)
#define fastio ios::sync_with_stdio(false)
#define check_min(a,b) a=min(a,b)
#define check_max(a,b) a=max(a,b)
using namespace std;
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
/*}
*/
const int MOD=1e9+7;
const int MAXN=3003;
int fact[MAXN];
int n,fa[MAXN],siz[MAXN];
int root(int x){
	return fa[x]=(fa[x]==x? x:root(fa[x]));
}
void merge(int u,int v){
	if(root(u)==root(v)) return ;
	siz[root(v)]+=siz[root(u)];
	fa[root(u)]=root(v);
}
int dp[2][2][MAXN][MAXN];
void add(int & A,int B){
	A+=B;
	if(A>=MOD) A-=MOD;
}
vector<int> calc(int len){
	if(len==1) return {1,1};
	rep(f,2) rb(i,1,len) memset(dp[0][f][i],0,sizeof(dp[0][f][i])),memset(dp[1][f][i],0,sizeof(dp[1][f][i]));
	dp[0][1][2][1]=1;
	dp[1][0][2][1]=1;
	dp[0][0][2][0]=1;
	vector<int> Ret(len+1,0);
	rb(i,2,len){
		rep(j,2)
			rep(f,2){
				rep(k,i)
					if(dp[j][f][i][k]){
						int val=dp[j][f][i][k];
						if(i==len){
							add(Ret[k],val);
							if(!j) add(Ret[k+1],val);
							if(!f) add(Ret[k+1],val);
						}
						else{
							add(dp[j][0][i+1][k],val);
							if(!f) add(dp[j][0][i+1][k+1],val);
							add(dp[j][1][i+1][k+1],val);
						}
					}
			}
	}
	return Ret;
}
vector<int> mul(vector<int> A,vector<int> B){
	vector<int> ret(A.size()+B.size()-1,0);
	rep(i,A.size()) rep(j,B.size()) add(ret[i+j],1ll*A[i]*B[j]%MOD);
	return ret;
}
int q[MAXN],p[MAXN];
int main(){
	fact[0]=1;
	rb(i,1,3000) fact[i]=1ll*fact[i-1]*i%MOD;
	scanf("%d",&n);
	rb(i,1,n) scanf("%d",&p[i]);
	rb(i,1,n) scanf("%d",&q[i]);
	rb(i,1,n) fa[i]=i,siz[i]=1;
	rb(i,1,n) merge(q[i],p[i]);
	vector<vector<int> > poly;
	rb(i,1,n) if(root(i)==i) poly.PB(calc(siz[i]));
	priority_queue<mp,vector<mp>,greater<mp> > heap;
	rep(i,poly.size()) heap.push(II(poly[i].size(),i));
	while(heap.size()>=2){
		int i,j;
		i=heap.top().SEC;
		heap.pop();
		j=heap.top().SEC;
		heap.pop();
		poly[i]=mul(poly[j],poly[i]);
		heap.push(II(poly[i].size(),i));
	}
	int i=heap.top().SEC;
	int ans=0;
	rep(j,poly[i].size()){
		if(j&1)
		add(ans,MOD-1ll*fact[n-j]%MOD*poly[i][j]%MOD);
		else
		add(ans,1ll*fact[n-j]%MOD*poly[i][j]%MOD);
	}
	cout<<ans<<endl;
	return 0;
}

H

很显然是费用流。

但是spfa会被卡。

需要用dijkstra费用流。

方法:令\(h[i]\)表示当前从\(s\)到\(i\)的最短路减去上一次增广前\(s\)到\(i\)的最短路。

然后考虑对\(h\)跑对短路。

边权\(u\rightarrow v,w\)变成\(w+dis[u]-dis[v]\)。可以发现这个总是\(\geq 0\)。

然后就做完了。

code:

#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define LL long long
#define IT iterator
#define PB push_back
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a<b;++a)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
#define ALL(a) a.begin(),a.end()
#define POB pop_back
#define ff fflush(stdout)
#define fastio ios::sync_with_stdio(false)
#define check_min(a,b) a=min(a,b)
#define check_max(a,b) a=max(a,b)
using namespace std;
//inline int read(){
//    int x=0;
//    char ch=getchar();
//    while(ch<'0'||ch>'9'){
//        ch=getchar();
//    }
//    while(ch>='0'&&ch<='9'){
//        x=(x<<1)+(x<<3)+(ch^48);
//        ch=getchar();
//    }
//    return x;
//}
#define int LL
typedef pair<LL,LL> mp;
/*}
*/
const int GRAPH_SIZE= 4e5+10;
int s=0,t=GRAPH_SIZE-1;
struct EDGE{
	int u,v,c,cos;
};
vector<EDGE> e;
vector<int> each[GRAPH_SIZE];
int maxflow,mincost;
int flow[GRAPH_SIZE];
int dis[GRAPH_SIZE],las[GRAPH_SIZE],h[GRAPH_SIZE];
bool fi=0;
int cnt=0;
bool spfa(){
	flow[s]=1e17;
	if(!fi){
		fi=1;
		fill(dis,dis+GRAPH_SIZE,1e17);
		dis[s]=0;
		rb(now,0,cnt*2){
			if(dis[now]==1e17) continue;
//			cerr<<now<<' '<<dis[now]<<endl;
			for(auto it:each[now]){
				int to,f,c;
				to=e[it].v;
				f=e[it].c;
				c=e[it].cos;
				if(f<=0) continue;
				assert(to>now);
				if(dis[to]>dis[now]+c){
					dis[to]=dis[now]+c;
					las[to]=it;
					flow[to]=min(flow[now],f);
				}
			}
		}
	}
	else{
		fill(h,h+GRAPH_SIZE,1e17);
		h[s]=0;
		priority_queue<mp,vector<mp>,greater<mp> > heap;
		heap.push(II(0,s));
		while(!heap.empty()){
			mp Now=heap.top();
			heap.pop();
			if(Now.FIR!=h[Now.SEC]) continue;
			int now=Now.SEC;
			for(auto it:each[now]){
				int to,f,c;
				to=e[it].v;
				f=e[it].c;
				c=e[it].cos+dis[now]-dis[to];
				if(f<=0) continue;
				if(h[to]>h[now]+c){
					h[to]=h[now]+c;
					las[to]=it;
					flow[to]=min(flow[now],f);
					heap.push(II(h[to],to));
				}
			}
		}
		rep(i,GRAPH_SIZE) dis[i]=min((LL)(1e17),dis[i]+h[i]);
	}
//	cerr<<dis[t]<<endl;
	return dis[t]<=1e16;
}
void KM(){
	while(spfa()){
		maxflow+=flow[t];
		mincost+=dis[t]*flow[t];
//		cout<<mincost<<" "<<maxflow<<endl;
		int now=t;
		while(now!=s){
			e[las[now]].c-=flow[t];
			e[las[now]^1].c+=flow[t];
			now=e[las[now]].u;
		}
	}
}
void make_edge(int U,int V,int C,int COS){
	EDGE tmp;
	tmp.u=U;
	tmp.v=V;
	tmp.c=C;
	tmp.cos=COS;
	e.PB(tmp);
	each[U].PB(e.size()-1);
	swap(tmp.u,tmp.v);
	tmp.c=0;
	tmp.cos=-COS;
	e.PB(tmp);
	each[V].PB(e.size()-1);
}
const int MAXN=2e5+10;
int n,m,k;
int in[MAXN],out[MAXN];
int belong[MAXN];
vector<int> g[MAXN],rg[MAXN];
int u[MAXN],v[MAXN];
stack<int> sta;
bool vis[MAXN];
map<mp,bool> app;
int x[MAXN];
void dfs(int now){
	vis[now]=1;
	for(auto it:g[now]) if(!vis[it]) dfs(it);
	sta.push(now);
}
void rdfs(int now){
	belong[now]=cnt;
	for(auto it:rg[now]) if(!belong[it]) rdfs(it);
}
signed main(){
	scanf("%lld%lld%lld",&n,&m,&k);
	rb(i,1,m){
		scanf("%lld%lld",&u[i],&v[i]);
		g[u[i]].PB(v[i]);
		rg[v[i]].PB(u[i]);
	}
//	cout<<g[1].size()<<endl;
	rb(i,1,n)
	if(!vis[i]) dfs(i);
	while(!sta.empty()){
		int now=sta.top();
		sta.pop();
		if(!belong[now]){
			++cnt;
			rdfs(now);
		}
	}
//	cout<<"!"<<cnt<<endl;
	rb(i,1,n){
		LL xx;
		scanf("%lld",&xx),x[belong[i]]+=xx;
	}
	rb(i,1,cnt) in[i]=i*2-1,out[i]=i*2;
	make_edge(s,in[belong[1]],k,0);
	rb(i,1,m){
		int U,V;
		U=belong[u[i]];
		V=belong[v[i]];
		if(U==0||V==0) continue;
		if(U!=V&&!app[II(U,V)]){
			app[II(U,V)]=1;
			assert(U<V);
//			cout<<out[U]<<" "<<in[V]<<endl;
			assert(out[U]<in[V]);
			make_edge(out[U],in[V],k,0);
		}
	}
//	cout<<cnt<<endl;
	rb(i,1,cnt) make_edge(in[i],out[i],1,-x[i]),make_edge(in[i],out[i],k,0);
	rb(i,1,cnt) make_edge(out[i],t,k,0);
	KM();
	cout<<-mincost<<endl;
	return 0;
}

标签:214,ABC,int,题解,dis,heap,now,dp,define
来源: https://www.cnblogs.com/QQQ0000/p/15142194.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有