CSP模拟6

T1一般图最小匹配

点击查看代码
#include<bits/stdc++.h>
using namespace std;

#define int long long
const int N=5000+107;
int n,m,a[N];

int read()
{
	int f=1,s=0;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){s=(s<<1)+(s<<3)+(ch^48);ch=getchar();}
	return f*s;
}

int f[N][N];

signed main()
{
	freopen("match.in","r",stdin);
	freopen("match.out","w",stdout);
	n=read(),m=read();
	for(int i=1;i<=n;i++) a[i]=read();
	sort(a+1,a+1+n);
	memset(f,0x3f,sizeof f);
	f[0][0]=0;
	f[1][0]=0;
	for(int i=2;i<=n;i++)
	{
		f[i][0]=f[i-1][0];
		for(int j=1;j<=m;j++)
		{
			f[i][j]=min(f[i-1][j],f[i-2][j-1]+a[i]-a[i-1]);
		}
	}
	
	printf("%lld",f[n][m]);
}

T2重定向

无任何算法,我们直接考虑即可,那我们先想,自然是把所有的空位按递增序列填就行,我们用一个 \(set\) 来维护,那我们考虑什么用删除,这删除肯定是越早用越好。

如果我们遍历到的数是 \(0\) ,我们直接比较它要被填上的数和它后面最小的数,如果后面的数更优,直接删掉,在加到 \(set\) 里面,否则直接为它附上值。

如果遍历到的数非零且后一个数也非零,我们直接比较判断即可。如果后一个数为 \(0\) ,我们比较那一位要填上的数和现在的数即可。

额,好像就没了……

点击查看代码
#include<bits/stdc++.h>
using namespace std;

const int N=4e5+107;
int n,a[N];
int nxt[N];
bool vis[N];
set<int>s;

int read()
{
	int f=1,s=0;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){s=(s<<1)+(s<<3)+(ch^48);ch=getchar();}
	return f*s;
}



int main()
{
	freopen("repeat.in","r",stdin);
	freopen("repeat.out","w",stdout);
	int T=read();
	while(T--)
	{
		s.clear();
		memset(vis,0,sizeof vis);
		memset(nxt,0x3f,sizeof nxt);
		n=read();
		for(int i=1;i<=n;i++) a[i]=read(),vis[a[i]]=1;
		for(int i=1;i<=n;i++) if(!vis[i]) s.insert(i);
		for(int i=n;i>=1;i--)
		{
			if(a[i+1]!=0) nxt[i]=min(nxt[i+1],a[i+1]);
			else nxt[i]=nxt[i+1];
		}
		
		int cnt=1,pos=0;
		for(int i=1;i<=n;i++)
		{
			if(a[i]==0)
			{
				if(*s.begin()>nxt[i])
				{
					pos=nxt[i];
					s.insert(nxt[i]);
					cnt--;
					break;
				}
			}
			else
			{
				if(a[i+1]==0&&*s.begin()<a[i])
				{
					pos=a[i],cnt--;
					s.insert(a[i]);
					break;
				}
				if(a[i+1]!=0&&a[i+1]<a[i])
				{
					pos=a[i],cnt--;
					s.insert(a[i]);
					break;
				}
			}
			if(a[i]==0) a[i]=*s.begin(),s.erase(*s.begin());
		}
		if(cnt) pos=a[n];
		
		for(int i=1;i<=n;i++)
		{
			if(a[i]==pos) continue;
			if(a[i]!=0) printf("%d ",a[i]);
			if(a[i]==0) 
			{
				printf("%d ",*s.begin());
				s.erase(*s.begin());
			}
		}
		printf("\n");
	}
}

T3 斯坦纳树

我们每经过一条路径,我们就把每个点标记上,在拓展一个新点的时候,我们直接让它往它和上一个节点的 \(lca\) 上跳,跳到第一个被标记且之前没有拓展过,我们把它存到 \(set\) 里,每拓展一个新数,如果 \(set\) 里面有对应的值,把它删掉,至于边权为 \(0\) ,我们直接合并成一个点。

点击查看代码
#include<bits/stdc++.h>
using namespace std;

const int N=1e6+107;
int n,p[N];
int bel[N];
int read()
{
	int f=1,s=0;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){s=(s<<1)+(s<<3)+(ch^48);ch=getchar();}
	return f*s;
}

int h[N<<1],to[N<<1],nxt[N<<1],tot;
void add(int x,int y)
{
	to[++tot]=y;
	nxt[tot]=h[x];
	h[x]=tot;
}

int f[N][40],dep[N];
void dfs(int u,int fa)
{
	f[u][0]=fa,dep[u]=dep[fa]+1;
	for(int i=1;i<=30;i++) f[u][i]=f[f[u][i-1]][i-1];
	for(int i=h[u];i;i=nxt[i])
	{
		int v=to[i];
		if(v==fa) continue;
		dfs(v,u);
	}
}

int get_lca(int x,int y)
{
	if(dep[x]<dep[y]) swap(x,y);
	for(int i=30;i>=0;i--)
	{
		if(dep[f[x][i]]>=dep[y])
		{
			x=f[x][i];
		}
	}
	if(x==y) return x;
	for(int i=30;i>=0;i--)
	{
		if(f[x][i]!=f[y][i])
		{
			x=f[x][i];
			y=f[y][i];
		}
	}
	return f[x][0];
}

set<int> s;
bool vis[N];
int flag[N];
void label(int x,int lca)
{
	if(vis[x]) return ;
	if(x==lca) return ;
	while(1)
	{
		vis[x]=1;
		x=f[x][0];
		if(x==lca) 
		{
			if(vis[x]&&!flag[x]) s.insert(x);
			else vis[x]=1;
			break;
		}
		if(vis[x]) 
		{
			if(!flag[x]) s.insert(x);
			break;
		}
	}
}

struct lmy
{
	int x,y,w;
}e[N];
bool comp(lmy a,lmy b)
{
	if(a.w==b.w) return a.x<b.x;
	return a.w<b.w;
}

int find(int x)
{
	return bel[x]==x?x:bel[x]=find(bel[x]);
}

signed main()
{
	freopen("tree.in","r",stdin);
	freopen("tree.out","w",stdout);
	n=read();
	for(int i=1;i<=n*2;i++) bel[i]=i;
	for(int i=1;i<n;i++) 
	{
		int x=read(),y=read(),w=read();
		if(y<x) swap(x,y);
		e[i]={x,y,w};
	}
	sort(e+1,e+1+n-1,comp);
	
	for(int i=1;i<n;i++)
	{
		if(e[i].w==0) 
		{
			int x=e[i].x,y=e[i].y;
			if(bel[x]==x&&bel[y]==y) bel[x]=n+i,bel[y]=n+i;
			else if(bel[x]!=x) bel[find(bel[y])]=find(bel[x]);
			else if(bel[y]!=y) bel[find(bel[x])]=find(bel[y]);
		}
		else break;
	}
	for(int i=1;i<=n*2;i++) bel[i]=find(bel[i]);
	for(int i=1;i<n;i++)
	{
		if(e[i].w==0) continue;
		add(bel[e[i].x],bel[e[i].y]);
		add(bel[e[i].y],bel[e[i].x]);
	}
	
	for(int i=1;i<=n;i++) p[i]=read();
	
	dfs(bel[p[1]],bel[p[1]]);
	flag[bel[p[1]]]=1;
	printf("1");
	
	for(int i=2;i<=n;i++)
	{
		s.erase(bel[p[i]]);
		int lca=get_lca(bel[p[i]],bel[p[i-1]]);
		flag[bel[p[i]]]=1;
		if(i==2) label(bel[p[i-1]],lca);
		label(bel[p[i]],lca);
		if(!s.empty()) printf("0");
		else printf("1");
	}
}
posted @   zhengchenxi  阅读(12)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· 使用C#创建一个MCP客户端
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· Windows编程----内核对象竟然如此简单?
点击右上角即可分享
微信分享提示