Ten graph questions of about 2000 difficulty of Codeforces Round 1

1.CF1187E Tree Painting

题目:

给定一棵n个点的树 初始全是白点

要求你做n步操作,每一次选定一个与一个黑点相隔一条边的白点,将它染成黑点,然后获得该白点被染色前所在的白色联通块大小的权值。

第一次操作可以任意选点。

求可获得的最大权值

思路:换根dp

s o n [ i ] son[i] son[i]表示第 i i i个点这棵树的大小, f [ i ] f[i] f[i]代表以 i i i点为根子树的答案

每个点获得的价值= s o n [ i ] son[i] son[i]+所有子树的 f f f

开始换根

在这里插入图片描述
f [ 1 ] = s o n [ 1 ] + f [ 2 ] + f [ 4 ] f[1]=son[1]+f[2]+f[4] f[1]=son[1]+f[2]+f[4]
f [ 4 ] = s o n [ 4 ] + f [ 9 ] f[4]=son[4]+f[9] f[4]=son[4]+f[9]
n e w new new f 1 = n e w f1 = new f1=new s o n 1 son1 son1+ f [ 2 ] f[2] f[2]
n e w new new s o n 1 = s o n [ 1 ] − s o n [ 4 ] son1 = son[1]-son[4] son1=son[1]son[4]
n e w new new f 4 f4 f4 = = = n e w new new s o n 4 + n e w son4 +new son4+new f 1 f1 f1 + f [ 9 ] f[9] f[9]
n e w new new s o n 4 = son4 = son4= s o n [ 1 ] son[1] son[1]
s o n [ 1 ] = n son[1]=n son[1]=n

经过愉快的代换后,我们就能得到 n e w new new f 4 f4 f4 = = = f [ 1 ] f[1] f[1]+ n − 2 ∗ s o n [ 4 ] n-2*son[4] n2son[4]

就可以写出最终答案啦:
(第10086次心碎教训告诉我要记得开longlong)

#include<bits/stdc++.h>
#define int long long
using namespace std;
constexpr int maxn=4e5+5;
int n,son[maxn],f[maxn],ans;
vector<int>e[maxn];
void dfs1(int u,int fa){
	son[u]=1;
	for(auto v:e[u]){
		if(v==fa)continue;
		dfs1(v,u);
		son[u]+=son[v];
		f[u]+=f[v];
	}
	f[u]+=son[u];
}
void dfs2(int u,int fa){
	ans=max(ans,f[u]);
	for(auto v:e[u]){
		if(v==fa)continue;
		f[v]=f[u]+n-2*son[v];
		ans=max(f[v],ans);
		dfs2(v,u);
	}
}
signed main(){
    cin>>n;
    for(int i=1;i<=n-1;i++){
    	int u,v;
    	cin>>u>>v;
    	e[u].push_back(v);
    	e[v].push_back(u);
	}
	dfs1(1,1);
	dfs2(1,1);
	cout<<ans;
}

2.CF796D Police Stations

题意:给定一棵树,树上有一些点是警察局,要求所有点到最近的警察局的距离不大于d,求最多能删几条边

思路:bfs

一开始把所有的警察局点加入队列进行bfs,记录每个点所属的警察局,如果边相连的两个点不属于同一个警察局则可删除

坑点:一个点可能有多个警察局,要判重(写程序10分钟debug半小时默默流泪)

#include<bits/stdc++.h>
using namespace std;
constexpr int maxn=3e5+5,inf=0x3f3f3f3f;
struct bb{
	int u,v;
}sb[maxn];
struct edge{
	int v,id;
};
vector<edge>e[maxn];
int f[maxn],vis[maxn],dis[maxn],a[maxn],fw[maxn];
int n,m,k,d,cnt,ans;
struct node{
	int v,fa,color,dis;
};
vector<int>jl;
void bfs(){
	queue<node>q;
	memset(dis,inf,sizeof dis);
	for(int i=1;i<=cnt;i++){
		q.push((node){a[i],a[i],i,0});
		fw[a[i]]=i;
	}
	while(!q.empty()){
		auto tt=q.front();
		q.pop();
		int u=tt.v;
		int fa=tt.fa;
		int col=tt.color;
		int dis=tt.dis;
		if(dis==d)continue;
		for(auto x:e[u]){
			int v=x.v;
			if(fw[v])continue;
			fw[v]=col;
			q.push((node){v,fa,col,dis+1});
		}
	}
}
int main(){
	cin>>n>>k>>d;
	for(int i=1;i<=k;i++){
		int x;
		cin>>x;
		if(!f[x]){
			f[x]=1;
			a[++cnt]=x;
		}
	}
	for(int i=1;i<=n-1;i++){
		int u,v;
		cin>>u>>v;
		sb[i].u=u;
		sb[i].v=v;
		e[u].push_back((edge){v,i});
		e[v].push_back((edge){u,i});
	}
	bfs();
	for(int i=1;i<=n-1;i++){
		if(fw[sb[i].u]!=fw[sb[i].v]){
		//	printf("%d ",res);
			ans++;
		}
	}
	cout<<ans<<endl;
	int res=0;
	for(int i=1;i<=n-1;i++){
		if(fw[sb[i].u]!=fw[sb[i].v]){
			printf("%d ",i);
			ans++;
		}
	}
}

3.CF909E Coprocessor

题意:有一堆任务,构成一个DAG,有的任务只能用主处理器完成,有的任务只能用副处理器完成,但是副处理器一次能完成当前一堆需要副处理器完成的任务,问遍历完整张图最少需要用多少次副处理器

思路:拓扑排序,贪心

只要当前还有点能用主处理器完成就将其加入队列继续拓扑,直到当前剩下的都得用副处理器,然后一次性处理完所有需要用副处理器的任务

#include<bits/stdc++.h>
using namespace std;
constexpr int maxn=1e5+5,inf=0x3f3f3f3f;
vector<int>e[maxn];
int f[maxn],n,m,cnt,ans,du[maxn];
void topo(){
	queue<int>q1,q2;
	for(int i=1;i<=n;i++){
		if(du[i]==0&&f[i]==0)q1.push(i);
		if(du[i]==0&&f[i]==1)q2.push(i);
	}
	while(q1.size()||q2.size()){
		while(!q1.empty()){
			int u=q1.front();
			q1.pop();
			for(auto v:e[u]){
				du[v]--;
				if(!du[v]){
					if(!f[v])q1.push(v);
					else q2.push(v);
				}
			}
		}
		if(q2.size())ans++;
		while(!q2.empty()){
			int u=q2.front();
			q2.pop();
			for(auto v:e[u]){
				du[v]--;
				if(!du[v]){
					if(!f[v])q1.push(v);
					else q2.push(v);
				}
			}
		}
	}
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>f[i];
	}
	for(int i=1;i<=m;i++){
		int u,v;
		cin>>v>>u;
		u++;
		v++;
		e[u].push_back(v);
		du[v]++;
	}
	topo();
	cout<<ans;
}

4.CF746G New Roads

#include<bits/stdc++.h>
using namespace std;
constexpr int maxn=2e5+5,inf=0x3f3f3f3f;
vector<int>e[maxn];
int n,m,t,k,a[maxn],f[maxn],cnt;
int main(){
	cin>>n>>t>>k;
	a[0]=1;
	for(int i=1;i<=t;i++){
		cin>>a[i];
	}
	if(a[t]>k||n-t<k){
		puts("-1");
		return 0;
	}
	for(int i=0;i<=t;i++){
		for(int j=1;j<=a[i];j++){
			e[i].push_back(++cnt);
		}
	}
	for(int i=0;i<a[1];i++){
		f[e[1][i]]=1;
	}
	for(int i=2;i<=t;i++){
		f[e[i][0]]=e[i-1][0];
	}
	int res=n-k-t;
	for(int i=2;i<=t;i++){
		for(int j=1;j<a[i];j++){
			if(res&&j<a[i-1]){
				f[e[i][j]]=e[i-1][j];
				res--;
			}
			else f[e[i][j]]=e[i-1][0];
		}
	}
	if(res){
		puts("-1");
		return 0;
	}
	cout<<n<<endl;
	for(int i=2;i<=n;i++){
		printf("%d %d\n",i,f[i]);
	}
	return 0;
}

5.CF243B Hydra

#include<bits/stdc++.h>
using namespace std;
constexpr int maxn=1e5+5,inf=0x3f3f3f3f;
vector<int>e[maxn],ans;
int n,m,t,h,k,tim,du[maxn],cnt,c[maxn],vis[maxn];
int main(){
	cin>>n>>m>>h>>t;
	for(int i=1;i<=m;i++){
		int u,v;
		cin>>u>>v;
		e[u].push_back(v);
		e[v].push_back(u);
		du[u]++,du[v]++;
	}
	for(int i=1;i<=m;i++){
		if(du[i]<=h)continue;
		for(auto j:e[i])c[j]=i;
		for(auto j:e[i]){
			tim++;
			int p=du[i]-1-h,q=0;
			ans.clear();
			for(auto k:e[j]){
				if(k!=i){
					if(c[k]==i&&p){
						p--;
						q++;
						vis[k]=tim;
						ans.push_back(k);
					}
					else if(c[k]!=i){
						q++;
						vis[k]=tim;
						ans.push_back(k);
					}
				}
				if(q==t)break;
			}
			if(q==t){
				int res=0;
				puts("YES");
				printf("%d %d\n",i,j);
				for(int k:e[i]){
					if(k!=j&&vis[k]!=tim){
						printf("%d ",k);
						res++;
					}
					if(res==h)break;
				}
				puts("");
				for(auto x:ans){
					printf("%d ",x);
				}
				return 0;
			}
		}
	}
	puts("NO");
}

6.CF59E Shortest Path

#include<bits/stdc++.h>
using namespace std;
constexpr int maxn=3005,maxm=4e5+5,inf=0x3f3f3f3f;

vector<int>mp[maxn][maxn];

struct edge{
	int v,nex;
}e[maxm];
int n,m,k,t,cnt=1,pre[maxm],vis[maxm],dis[maxm];
int head[maxm];
bool judge(int x,int y,int z){
	for(auto t:mp[x][y]){
		if(t==z)return true;
	}
	return false;
}
void add(int u,int v){
	e[++cnt].v=v;
	e[cnt].nex=head[u];
	head[u]=cnt;
}
void pri(int i){
	if(i){
		pri(pre[i]);
		printf("%d ",e[i].v);
	}
	else printf("1 ");
}
bool bfs(){
	queue<pair<int,int>>q;
	dis[1]=0;
	q.push({1,0});
	while(!q.empty()){
		auto x=q.front();
		q.pop();
		int u=x.first;
		int id=x.second;
		for(int i=head[u];i;i=e[i].nex){
			int v=e[i].v;
			int qq=e[id^1].v;
			if(vis[i]||judge(qq,u,v))continue;
			dis[i]=dis[id]+1;
			pre[i]=id;
			vis[i]=1;
			if(v==n){
				printf("%d\n",dis[i]);
				pri(i);
				return true;
			}
			q.push({v,i});
		}
	}
	return false;
}
int main(){
	cin>>n>>m>>k;
	for(int i=1;i<=m;i++){
		int u,v;
		cin>>u>>v;
		add(u,v);
		add(v,u);
	}
	for(int i=1;i<=k;i++){
		int x,y,z;
		cin>>x>>y>>z;
		mp[x][y].push_back(z);
	}
	if(!bfs())puts("-1");
}

7.CF237E Build String

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
const int inf=0x3f3f3f3f,maxn=505,maxm=10005;
struct edge{
	int nex,v,cost,flow;
}e[maxm];
int head[maxn],cnt=1;
int n,m,k,T,w[maxn];
string s,p;
int a[maxn][maxn],b[maxn];
inline void add_edge(int u,int v,int cost,int flow){
	e[++cnt].v=v;
	e[cnt].cost=cost;
	e[cnt].flow=flow;
	e[cnt].nex=head[u];
	head[u]=cnt;
	e[++cnt].v=u;
	e[cnt].cost=-cost;
	e[cnt].flow=0;
	e[cnt].nex=head[v];
	head[v]=cnt;
}
int inque[maxn],dis[maxn],flow[maxn],pre[maxn],last[maxn];
bool spfa(int s,int t){
	queue<int>q;
	memset(dis,0x3f,sizeof dis);
	memset(flow,0x3f,sizeof flow);
	memset(inque,0,sizeof inque);
	q.push(s);
	inque[s]=1;
	dis[s]=0;
	pre[t]=-1;
	while(!q.empty()){
		int u=q.front();
		q.pop();
		inque[u]=0;
		for(int i=head[u];i;i=e[i].nex){
			int v=e[i].v;
			if(dis[v]>dis[u]+e[i].cost&&e[i].flow){
				dis[v]=dis[u]+e[i].cost;
				pre[v]=u;
				last[v]=i;
				flow[v]=min(flow[u],e[i].flow);
				if(!inque[v]){
					q.push(v);
					inque[v]=1;
				}
			}
		}
	}
	if(pre[t]!=-1)return true;
	return false;
}
inline pair<int,int> mcmf(int s,int t){
	int maxflow=0;
	int mincost=0;
	while(spfa(s,t)){
		int u=t;
		maxflow+=flow[t];
		mincost+=flow[t]*dis[t];
		while(u!=s){
			e[last[u]].flow-=flow[t];
			e[last[u]^1].flow+=flow[t];
			u=pre[u];
		}
	}
	return {maxflow,mincost};
}
int main(){
	cin>>p;
	cin>>n;
	int st=502;
	int ed=503;
	for(int i=1;i<=n;i++){
		cin>>s>>w[i];
		for(auto x:s){
			a[i][x-'a'+1]++;
		}
		add_edge(st,i,0,w[i]);
	}//s到n个串 
	for(auto x:p){
		b[x-'a'+1]++;
	}//p串 
	for(int i=1;i<=n;i++){
		for(int j=1;j<=26;j++){
			if(a[i][j]){
				add_edge(i,n+j,i,a[i][j]);
			}
		}
	}
	for(int i=1;i<=26;i++){
		if(b[i]){
			add_edge(n+i,ed,0,b[i]);
		}
	}
	auto x=mcmf(st,ed);
	if(x.first==p.length())cout<<x.second;
	else cout<<-1;
}

8.CF793D Presents in Bankopolis

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
constexpr int inf=0x3f3f3f3f,maxn=85;
int f[maxn][maxn][maxn][2];
int n,m,k,ans=inf; 
struct edge{
	int v,w;
};
vector<edge>e[maxn];
int find(int l,int r,int res,int col){
	if(f[l][r][res][col]!=-1)return f[l][r][res][col];
	if(res==0)return f[l][r][res][col]=0;
	int u=(col==0?l:r);
	int qq=inf;
	for(auto x:e[u]){
		int v=x.v;
		int w=x.w;
		if(v>l&&v<r)qq=min(qq,min(find(l,v,res-1,1),find(v,r,res-1,0))+w);
	}
	return f[l][r][res][col]=qq;
}
int main(){
	cin>>n>>k>>m;
	for(int i=1;i<=m;i++){
		int u,v,w;
		cin>>u>>v>>w;
		e[u].push_back((edge){v,w});
	}
	memset(f,-1,sizeof f);
	for(int i=1;i<=n;i++){
		ans=min({ans,find(0,i,k-1,1),find(i,n+1,k-1,0)});
	}
	if(ans==inf)puts("-1");
	else cout<<ans;
	return 0;
}

写完了没保存刷新了没了,自闭了,不写了

9.CF803E Roma and Poker

题意:给定一个由 W , D , L , ? W,D,L,? W,D,L,? 构成的长度为 n n n 的字符串,并给定一个常数 k k k ,你要替换字符串中的所有 ? ? ? ,使得原串的 W , L W,L W,L 出现次数之差的绝对值 = k =k =k ,且除原串外任意前缀的 W , L W,L W,L 出现次数之差的绝对值 k k k ,求构造出的字符串,无解输出 NO,否则输出构造后的字符串。

思路:记忆化搜索

#include<bits/stdc++.h>
using namespace std;
constexpr int maxn=1005,inf=0x3f3f3f3f;
string s;
long long n,m,k;
bool f[1005][1005];
bool dfs(int now,int x){
	if(now==n&&abs(x)==k)return 1;
	if(now==n||abs(x)>=k)return 0;
	if(f[now][x])return 0;
	f[now][x]=1;
	if(s[now]=='W')return dfs(now+1,x+1);
	if(s[now]=='D')return dfs(now+1,x);
	if(s[now]=='L')return dfs(now+1,x-1);
	if(dfs(now+1,x+1)){
		s[now]='W';
		return 1;
	}
	if(dfs(now+1,x  )){
		s[now]='D';
		return 1;
	}
	if(dfs(now+1,x-1)){
		s[now]='L';
		return 1;
	}
}
int main(){
	cin>>n>>k;
	cin>>s;
	if(dfs(0,0))cout<<s;
	else cout<<"NO";
}

10.CF859E Desk Disorder

题意:有 N N N 个人和 2 N 2N 2N 个座位。告诉你这 N N N 个人它们现在的座位。以及它们想去的座位。
每个人可以去它们想去的座位或者就坐在原来的座位上。
新的座位安排和旧的座位安排,都不允许一个座位被两个人占据的情况。
问你新的座位安排的方案数。

思路:并查集,分类讨论

只有三种情况:

1.树

2.环or基环树

3.自环

用并查集维护,如果当前子图有自环的环无论如何都不能动,方案为1,如果是树方案数为树的节点数,如果是环or基环树,方案数为2(只有环上的可以动)

最后相乘即可

#include<bits/stdc++.h>
#define int long long
using namespace std;
constexpr int maxn=2e5+5,inf=0x3f3f3f3f,mod=1e9+7;
int f[maxn],n,m,s[maxn],c[maxn],ans=1,h[maxn];
int find(int x){
	if(f[x]==x)return x;
	else return f[x]=find(f[x]);
}
inline void hb(int x,int y){
	int fx=find(x);
	int fy=find(y);
	if(fx!=fy){
		h[fy]|=h[fx];
		s[fy]+=s[fx];
		c[fy]+=c[fx]+1;
		f[fx]=fy;
	}
	else if(fx==fy){
		c[fy]++;
	}
}
signed main(){
	cin>>n;
	for(int i=1;i<=2*n;i++){
		f[i]=i;
		s[i]=1;
	}
	for(int i=1;i<=n;i++){
		int u,v;
		cin>>u>>v;
		if(u==v)h[u]=h[v]=1;
		hb(u,v);
	}
	for(int i=1;i<=2*n;i++){
		if(f[i]==i&&s[i]!=1&&!h[i]){
			if(s[i]==c[i]){
				ans=ans*2%mod;
			}
			else if(s[i]==c[i]+1){
				ans=ans*s[i]%mod;
			}
		}
	}
	cout<<ans%mod;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值