其他分享
首页 > 其他分享> > 省选模拟13

省选模拟13

作者:互联网

T1

费用流,拆点,把点按奇偶分类

偶数的直接拆成 \(\frac{a_i}{2}\) ,奇数的也一样,然后枚举哪一边的流量多,再给他加上就行

Code
#include<bits/stdc++.h>
#define int long long
#define rint signed
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
int n,ans=inf,p,U,S,T;
int a[60],c[60][60],trans[60];
int L[60],R[60];
namespace FLOW{
	int COST;
	int dis[1010],q[1010],h,t;
	int head[1010],ver[6000],to[6000],edge[6000],cost[6000],tot=1;
	bool inq[1010],vis[1010];
	inline void add(int x,int y,int z,int w){
		ver[++tot]=y;edge[tot]=z;cost[tot]= w;to[tot]=head[x];head[x]=tot;
		ver[++tot]=x;edge[tot]=0;cost[tot]=-w;to[tot]=head[y];head[y]=tot;
	}
	inline bool spfa(){
		for(int i=1;i<=T;i++) dis[i]=inf,inq[i]=0;
		dis[S]=0,q[h=t=1]=S,inq[S]=1;memset(vis,0,sizeof(vis));
		while(h<=t){
			int x=q[h++];inq[x]=0;
			for(int i=head[x];i;i=to[i]) if(edge[i]){
				int y=ver[i];
				if(dis[y]>dis[x]+cost[i]){
					dis[y]=dis[x]+cost[i];
					if(!inq[y]) q[++t]=y,inq[y]=1;
				}
			}
		}
		return dis[T]!=inf;
	}
	int dfs(int x,int in){
		if(x==T) return in;
		int res=in,go;vis[x]=1;
		for(int i=head[x];i;i=to[i]) if(edge[i]){
			int y=ver[i];
			if(vis[y]) continue;
			if(dis[y]==dis[x]+cost[i]){
				go=dfs(y,min(res,edge[i]));
				res-=go,edge[i]-=go,edge[i^1]+=go;
				COST+=go*cost[i];
			}
			if(!res) break;
		}
		return in-res;
	}
	inline void clear(){for(int i=1;i<=T;i++) head[i]=0;tot=1;COST=0;}
	inline int MinCost(){while(spfa()) dfs(S,inf);return COST;}
}using FLOW::add;
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	freopen("match.in","r",stdin);
	freopen("match.out","w",stdout);
	n=read();S=n*2+1,T=n*2+2;
	for(int i=1;i<=n;i++) a[i]=read();
	for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) c[i][j]=read();
	for(int i=1;i<=n;i++) if(a[i]&1) trans[++p]=i;if(p&1) puts("-1"),exit(0);
	U=(1<<p)-1;
	for(int sta=0;sta<=U;sta++) if(__builtin_popcount(sta)==p/2){
		for(int i=1;i<=n;i++) L[i]=R[i]=a[i]/2;
		for(int i=1;i<=p;i++) if(sta>>(i-1)&1) L[trans[i]]++;else R[trans[i]]++;
		FLOW::clear();
		for(int i=1;i<=n;i++) add(S,i,L[i],0),add(i+n,T,R[i],0);
		for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) add(i,j+n,inf,c[i][j]);
		ans=min(ans,FLOW::MinCost());
	}
	printf("%lld\n",ans);
	return 0;
}

T2

对于每个节点都维护一些线段,只用记录他的左右端点

合并的时候考虑哪一条线段作为第一条线段,再用状压 \(dp\) 出以这个线段为左端点时的最小的右端点

注意把劣的去掉,同时在状压的过程中记录合并的顺序

Code


#include<bits/stdc++.h>
#define int long long
#define rint signed
#define inf 0x3f3f3f3f
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
int n;
struct seg{
	int l,r,id;
	inline bool operator<(const seg &b)const{return (l==b.l)?r<b.r:l<b.l;}
};
map<int,seg>mp;
vector<int>g[100010],ans[100010];
vector<seg>vec[100010],tmp;
int f[100010],ff[100010],son[100010],id[100010];
void dfs1(int x){
	if(!g[x].size()) return ;int p=0;
	for(auto y:g[x]) dfs1(y),son[y]=++p;
	if(g[x].size()==1) return swap(vec[x],vec[g[x][0]]),void();
	int U=(1<<(g[x].size()-1))-1;
	mp.clear();tmp.clear();seg t;
	for(int i=0;i<g[x].size();i++){
		int y=g[x][i];
		for(int j=0;j<vec[y].size();j++){
			t=vec[y][j];t.id=i;
			tmp.emplace_back(t);
		}
	}
	sort(tmp.begin(),tmp.end());reverse(tmp.begin(),tmp.end());
	int pre=inf;
	for(int i=0;i<tmp.size();i++){
		t=tmp[i];
		int y=g[x][t.id],l=t.l,r=t.r,pp=0;
		for(int j=0;j<g[x].size();j++) if(j!=t.id) id[++pp]=g[x][j];
		for(int sta=0;sta<=U;sta++) f[sta]=inf;f[0]=r,ff[0]=son[y];
		for(int sta=0;sta<=U;sta++) if(f[sta]<=100000){
			t.l=f[sta]+1,t.r=0;
			for(int j=1,pos,ed;j<=pp;j++) if(!((sta>>(j-1))&1)){
				ed=vec[id[j]].size();
				pos=lower_bound(vec[id[j]].begin(),vec[id[j]].end(),t)-vec[id[j]].begin();
				if(pos!=ed&&vec[id[j]][pos].r<f[sta|1<<(j-1)]){
					f[sta|1<<(j-1)]=vec[id[j]][pos].r;
					ff[sta|1<<(j-1)]=ff[sta]*10+son[id[j]];
				}
			}
		}
		if(f[U]<=100000&&f[U]<pre) pre=f[U],mp[l].r=f[U],mp[l].id=ff[U];
	}
	auto iter=mp.begin();
	if(iter==mp.end()) puts("No"),exit(0);
	while(iter!=mp.end()){
		t=(*iter).second,t.l=(*iter).first;
		vec[x].emplace_back(t);
		iter++;
	}
}
void dfs2(int x,int l,int r){
	if(g[x].size()==0) return ans[x].emplace_back(l),void();
	if(g[x].size()==1) return ans[x].emplace_back(g[x][0]),swap(vec[x],vec[g[x][0]]),dfs2(g[x][0],l,r);
	seg t=(seg){l,r,0};
	int pos=lower_bound(vec[x].begin(),vec[x].end(),t)-vec[x].begin();
	int id=vec[x][pos].id;
	while(id) ans[x].emplace_back(g[x][id%10-1]),id/=10;
	reverse(ans[x].begin(),ans[x].end());t.r=0;
	for(int i=0;i<ans[x].size();i++){
		int y=ans[x][i];
		int pos=lower_bound(vec[y].begin(),vec[y].end(),t)-vec[y].begin();
		t=vec[y][pos];
		dfs2(y,t.l,t.r);
		t.l=t.r+1;t.r=0;
	}
}
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	freopen("sort.in","r",stdin);
	freopen("sort.out","w",stdout);
	n=read();
	for(int i=1,op,k;i<=n;i++){
		op=read();
		if(op==1){
			k=read();
			for(int j=1;j<=k;j++) g[i].emplace_back(read());
		}else{
			k=read();
			for(int j=1,x;j<=k;j++){x=read();vec[i].emplace_back((seg){x,x,0});}
			sort(vec[i].begin(),vec[i].end());
		}
	}
	dfs1(1);puts("Yes");
	dfs2(1,vec[1][0].l,vec[1][0].r);
	for(int i=1;i<=n;i++,puts("")) for(int j=0;j<ans[i].size();j++) printf("%lld ",ans[i][j]);
	return 0;
}

T3

考虑 \(O(n^2)\) 的暴力,对每个点都把他能直接传染到的点和他连边

然后再用 \(tarjan\) 缩点,最后剩下几个没有入度的点,答案就是几

考虑用点分治来优化这个过程

对于每个分治中心,把所有的路径长度都找出来

对每个长度都分别建立虚点,由长向短依次连边

再看每个点,由长度大于等于他的第一个虚点连边,再由他向他能传染到的跨过分治中心的最远的点连边

这里只考虑跨过分治中心的,没有跨过的会在其他地方考虑到

最后再用 \(tarjan\) 缩点,找到没有入度的点就行

Code
#include<bits/stdc++.h>
#define int long long
#define rint signed
#define inf 0x3f3f3f3f
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
int n,ans,deg[4300010],r[300010],N;
rint head[300010],ver[600010],to[600010],tot;
int edge[600010];
rint dfn[4300010],low[4300010],clo,mn[4300010];
rint scc[4300010],col,stk[4300010],p;
int S,rt,mxdis;
rint siz[4300010],mx[4300010],id[4300010];
bool vis[4300010];
vector<rint>g[4100000],gg[3420000];
vector<int>vec;
queue<int>q;
inline void add(rint x,rint y,rint z){ver[++tot]=y;edge[tot]=z;to[tot]=head[x];head[x]=tot;}
void tarjan(int x){
	dfn[x]=low[x]=++clo;vis[x]=1;stk[++p]=x;
	for(auto y:g[x]){
		if(!dfn[y]){tarjan(y);low[x]=min(low[x],low[y]);}
		else if(vis[y]) low[x]=min(low[x],dfn[y]);
	}
	if(dfn[x]==low[x]){
		rint k;col++;mn[col]=N+1;
		do{k=stk[p--];scc[k]=col;vis[k]=0;mn[col]=min(mn[col],k);}while(k!=x);
	}
}
void getrt(int x,int fa){
	siz[x]=1,mx[x]=0;
	for(rint i=head[x];i;i=to[i]){
		int y=ver[i];
		if(y==fa||vis[y]) continue;
		getrt(y,x);siz[x]+=siz[y];mx[x]=max(mx[x],siz[y]);
	}
	mx[x]=max(mx[x],(rint)S-siz[x]);
	if(mx[x]<mx[rt]) rt=x;
}
void getdis(int x,int fa,int dis){
	mxdis=max(mxdis,dis);vec.emplace_back(dis);
	for(rint i=head[x];i;i=to[i]){
		int y=ver[i];
		if(y==fa||vis[y]) continue;
		getdis(y,x,dis+edge[i]);
	}
}
void dfs2(int x,int fa,int dis){
	int pos=lower_bound(vec.begin(),vec.end(),dis)-vec.begin(),range;
	g[id[pos]].emplace_back(x);
	range=min(mxdis,r[x]-dis);
	if(range>=0){
		pos=upper_bound(vec.begin(),vec.end(),range)-vec.begin();
		if(pos) g[x].emplace_back(id[pos-1]);
	}
	for(rint i=head[x];i;i=to[i]){
		int y=ver[i];
		if(y==fa||vis[y]) continue;
		dfs2(y,x,dis+edge[i]);
	}
}
inline void calc(int x){
	vec.clear();mxdis=-1;getdis(x,0,0);
	sort(vec.begin(),vec.end());
	vec.erase(unique(vec.begin(),vec.end()),vec.end());
	for(rint i=0;i<vec.size();i++) id[i]=++N;dfs2(x,0,0);
	for(rint i=1;i<vec.size();i++) g[id[i]].emplace_back(id[i-1]);
}
void solve(int x){
	vis[x]=1;calc(x);
	for(rint i=head[x];i;i=to[i]){
		int y=ver[i];
		if(vis[y]) continue;
		rt=0;getrt(y,0);
		S=siz[y];mx[rt=0]=inf;
		getrt(y,0);solve(rt);
	}
}
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	freopen("infect.in","r",stdin);
	freopen("infect.out","w",stdout);
	N=n=read();for(rint i=1;i<=n;i++) r[i]=read();
	for(rint i=1,x,y,z;i<n;i++){
		x=read(),y=read(),z=read();
		add(x,y,z);add(y,x,z);
	}
	S=n;mx[rt=0]=inf;
	getrt(1,0);solve(rt);
	memset(vis,0,sizeof(vis));
	for(rint i=1;i<=N;i++) if(!dfn[i]) tarjan(i);
	for(rint i=1;i<=N;i++) for(auto y:g[i]) if(scc[i]!=scc[y]) deg[scc[y]]++,gg[scc[i]].emplace_back(scc[y]);
	for(rint i=1;i<=col;i++) if(!deg[i]) q.push(i);
	cerr<<col<<endl;
	memset(vis,0,sizeof(vis));
	while(!q.empty()){
		int x=q.front();q.pop();
		if(!vis[x]&&mn[x]<=n) ans++,vis[x]=1;
		for(auto y:gg[x]){
			deg[y]--,vis[y]|=vis[x];
			if(!deg[y]) q.push(y);
		}
	}
	printf("%lld\n",ans);
	return 0;
}

标签:13,ch,省选,rint,++,int,vec,模拟,define
来源: https://www.cnblogs.com/MaxQAQ/p/15881760.html