ICode9

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

冲刺省选2月10日第十三场

2022-02-11 08:01:31  阅读:179  来源: 互联网

标签:10 第十三 传染 省选 int cost vct include cc


因为只会打暴力,而且发现旁边的人切题了(然而这个人做法假了)

于是这场心态崩了,导致不能很专注的思考性质和检查代码

所以还是没能做到不被别人影响

T1 一般图带权多重匹配

垃圾费用流题,然而我没想到

考虑如何将匹配的过程转化,发现匹配的过程是两个点同时减 \(1\)

于是就可以将每个点拆成两个点,并分别与s和t连\(\frac{a_i}{2}\)的流量

分别考虑奇数和偶数,偶数按照上述连边即可

奇数最后一定是两两匹配,于是状压枚举一半的奇数,分别与 \(s\)和 \(t\)补上少的 \(1\)

T3 传染

\(O(n^2)\) 暴力,从 x 点一直传染直到不能传染,就从 x 向最终能传染到的点连边

然后强联通缩点,dag 上没有入度的点的个数即为答案

考虑一种方法优化 dfs ,即能将传染的过程在节点上打标记,一个点只会被传染一次

考虑点分树,由于点分树上两点的 lca 是两点在原树路径上一点,于是可以枚举 x 的祖先 f 并按距离升序枚举 f 的子树内的点,此时有了单调性于是可以标记,从所有点开始传染一边的复杂度变成了 \(O(n\log n)\)

接着思考从 x 传染的过程,本质上是从 x 沿着 dag 走到没有出度的点

于是有了这样一种方法,可以遍历点并开始传染,然后将所有能传染到的点(包括自身)逆序加入到一个 vector,在遍历完后将 vector 翻转

不难发现,这样的操作后若将 vector 内的元素替换成所属的 dag 的节点,那 vector 中的顺序满足 x 一定在 x 能到的点之后出现,此时可以再传染一边,扫到的没有被标记的点的个数为答案

代码

T1

#include<cmath>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#define il inline
const int N=6e3+11;
const int inf=0x3f3f3f3f;
using namespace std;
struct qxxx{
	int v,next,w,cost;
}cc[2*N];
bool vis[N];
int n,s,t;
int a[N];
int d[N],path[N];
int first[N],cnt;
int c[N][N];
queue<int>dui;
vector<int>odd;
il int min_(int x,int y){return x>y?y:x;}
il int read(){
	int s=0;char ch=getchar();
	while(ch>'9'||ch<'0')ch=getchar();
	while(ch>='0'&&ch<='9')s=(s<<1)+(s<<3)+(ch^48),ch=getchar();
	return s;
}
il int js(int x){
	int ans=0;
	for(;x;x-=(x&-x),++ans);
	return ans;
}
il void qxx(int u,int v,int w,int c){
	cc[++cnt]={v,first[u],w,c};
	first[u]=cnt;
}
il void add(int u,int v,int w,int c){
	qxx(u,v,w,c);
	qxx(v,u,0,-c);
}
il void init(){
	cnt=1;
	memset(cc,0,sizeof(cc));
	memset(first,0,sizeof(first));
}
bool spfa(){
	memset(d,0x3f,sizeof(d));
	memset(vis,0,sizeof(vis));
	memset(path,0,sizeof(path));
	int x;d[s]=0,vis[s]=1;dui.push(s);
	while(dui.size()){
		x=dui.front();
		dui.pop();vis[x]=0;
		for(int v,i=first[x];i;i=cc[i].next){
			if(!cc[i].w)continue;
			v=cc[i].v;
			if(d[v]>cc[i].cost+d[x]){
				path[v]=i;
				d[v]=cc[i].cost+d[x];
				if(!vis[v]){vis[v]=1,dui.push(v);}
			}
		}
	}return d[t]!=inf;
}
int cost_flow(){
	int mn=inf,cost=0;
	while(spfa()){
		mn=inf;
		for(int i=path[t];i;i=path[cc[i^1].v]){
			mn=min_(mn,cc[i].w);
		}
		for(int i=path[t];i;i=path[cc[i^1].v]){
			cc[i].w-=mn;
			cc[i^1].w+=mn;
			cost+=mn*cc[i].cost;
		}
	}return cost;
}
int main(){
	freopen("match.in","r",stdin),freopen("match.out","w",stdout);
	n=read();
	for(int i=1;i<=n;++i){
		a[i]=read();
		if(a[i]&1)odd.push_back(i);
	}
	for(int i=1;i<=n;++i)for(int j=1;j<=n;++j)c[i][j]=read();
	if(odd.size()&1){cout<<-1<<endl;return 0;}
	s=2*n+1,t=2*n+2;
	int ans=inf;
	for(int i=0;i<(1<<odd.size());++i){
		if(js(i)!=(odd.size()>>1))continue;
		init();
		for(int j=1;j<=n;++j){
			if(a[j]&1)continue;
			add(s,j,a[j]>>1,0);
			add(j+n,t,a[j]>>1,0);
		}
		for(int x,j=0;j<odd.size();++j){
			x=odd[j];
			if((1<<j)&i){
				add(s,x,1+(a[x]>>1),0);
				add(x+n,t,a[x]>>1,0);
			}
			else{
				add(s,x,a[x]>>1,0);
				add(x+n,t,1+(a[x]>>1),0);
			}
		}
		for(int j=1;j<=n;++j)
			for(int k=1;k<=n;++k){
				add(j,k+n,inf,c[j][k]);
			}
		ans=min_(ans,cost_flow());
	}cout<<ans<<endl;
}

T3

#include<cmath>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define il inline
const int inf=1e9;
const int N=3e5+11;
struct vct_{
	int v,d;vct_(){}
	vct_(int v_,int d_){v=v_,d=d_;}
	friend bool operator<(vct_ a,vct_ b){
		return a.d<b.d;
	}
};
bool vis[N];
int n;
int mx_siz,rt;
int p[N];
int siz[N],r[N];
vector<int>tp,tmp;
vector<vct_>vct[N];
vector<vct_>cs[N],vs[N];
il int max_(int x,int y){return x>y?x:y;}
il int min_(int x,int y){return x>y?y:x;}
il int read(){
	int s=0;char ch=getchar();
	while(ch>'9'||ch<'0')ch=getchar();
	while(ch>='0'&&ch<='9')s=(s<<1)+(s<<3)+(ch^48),ch=getchar();
	return s;
}
void get_siz(int x,int fa){
	siz[x]=1;int v;
	for(vct_ y : vct[x]){
		v=y.v;if(v==fa||vis[v])continue;
		get_siz(v,x);
		siz[x]+=siz[v];
	}
}
void get_rt(int x,int fa,int now){
	int v,mx=0;
	for(vct_ y : vct[x]){
		v=y.v;if(v==fa||vis[v])continue;
		get_rt(v,x,now);
		mx=max_(mx,siz[v]);
	}mx=max_(mx,now-siz[x]);
	if(mx_siz>mx)mx_siz=mx,rt=x;
}
void dfs(int x,int fa,int dep,int root){
	if(dep>inf)return;int v;
	vs[root].push_back({x,dep});
	cs[x].push_back({root,dep});
	for(vct_ y : vct[x]){
		v=y.v;if(v==fa||vis[v])continue;
		dfs(v,x,dep+y.d,root);
	}
}
void div(int x){
	vis[x]=1;
	dfs(x,0,0,x);
	sort(vs[x].begin(),vs[x].end());
	int v;for(vct_ y : vct[x]){
		v=y.v;if(vis[v])continue;
		mx_siz=inf;get_siz(v,0);
		get_rt(v,0,siz[v]);div(rt);
	}
}
void maketp(int x){
	vis[x]=1;
	for(vct_ e : cs[x]){
		while(p[e.v]<(int)vs[e.v].size()){
			vct_ f=vs[e.v][p[e.v]++];
			if(vis[f.v])continue;
			if(f.d+e.d>r[x]){--p[e.v];break;}
			maketp(f.v);
		}
	}tp.push_back(x);
}
int main(){
	freopen("infect.in","r",stdin),freopen("infect.out","w",stdout);
	n=read();for(int i=1;i<=n;++i)r[i]=read();
	for(int x,y,z,i=1;i<n;++i){
		x=read(),y=read(),z=read();
		vct[x].push_back(vct_(y,z));
		vct[y].push_back(vct_(x,z));
	}
	mx_siz=inf,get_siz(1,0),get_rt(1,0,n);div(rt);
	memset(vis,0,sizeof(vis));
	for(int i=1;i<=n;++i){
		if(vis[i])continue;
		maketp(i);
	}
	tmp=tp;tp.clear();
	reverse(tmp.begin(),tmp.end());
	memset(p,0,sizeof(p));
	memset(vis,0,sizeof(vis));
	int ans=0;
	for(int v : tmp){
		if(vis[v])continue;
		maketp(v);++ans;
	}cout<<ans<<endl;
}

标签:10,第十三,传染,省选,int,cost,vct,include,cc
来源: https://www.cnblogs.com/sitiy/p/15881745.html

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

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

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

ICode9版权所有