Codeforces Round #819 C - D

C

题意

给定一个合法的括号序列,如果区间【l, r】之间是一个合法序列,那么就在l, r之间连一条边 问最后有几个连通块

思路

相邻的两个括号并不会使答案+2,只有嵌套的括号才能使答案增加,而嵌套的括号结尾必然是’))'我们只需要维护‘)’的连续出现次数,如果大于1则增加答案

代码实现

void solve()
{
	int n;
	cin >> n;
	string s;
	cin >> s;
	int res = 0;
	int cnt = 0;
	
	for (int  i = 0 ; i < s.size(); i ++)
	{
		if (s[i] == '(')
		{
			if(cnt)res += cnt - 1;
			cnt = 0;
		}
		else cnt ++;
	}
	
	cout << res + cnt << endl;
}

D

题意

给定n个点,m条边 m<= n + 2且给定的图联通无重边 选择一些边为red , 一些边为blue
请问边选定后,能使两个图的得到最小连通块的方案是什么,(打印任意)

思路

根据最小生成树kruskal的推论,一条边可以减少一个连通块,那么我们最好的操作就是求一个最小生成树,那么还有一个小问题,就是剩下的三条边可能是个环,这样答案不是最佳。解决方案是判断剩下的三条边如果是环,我们任意将环上一边变成另一种颜色,在将这边上的某一点的所有边的零一点全变色, 这样能构造出一个没有环的图

代码实现

#include<bits/stdc++.h>
#define x first
#define y second
#define int long long
#define endl '\n'
using namespace std;
typedef pair<int, int> PII;
typedef long long LL;
const int N = 2e5 + 10, mod = 1e9 + 7, INF = 1e9;
PII seg[N];
int p[N];
char ans[N];
int find (int x)
{
	if (p[x] != x) p[x] = find (p[x]);
	
	return p[x];
}
void solve()
{
	int n, m;
	cin >> n >> m;
	
	for (int i = 1 ; i <= m ; i ++)
	{
		int l, r;
		cin >> l >> r;
		seg[i] = {l, r};
	}
	
	vector<int> red;
	vector<vector<pair<int, int>>> g (n + 2);
	
	for (int i = 1 ; i <= n ; i ++) p[i] = i;
	
	for (int i = 1 ; i <= m ; i ++)
	{
		int l = seg[i].x, r = seg[i].y;
		
		if (find (l) != find (r))
		{
			ans[i] = '1';
			p[find(l)] = find (r);
			g[l].push_back ({r, i});
			g[r].push_back ({l, i});
		}
		else ans[i] = '0', red.push_back (i);
	}
	
	if (m == n + 2)
	{
		set<int> S;
		
		for (auto x : red)
			S.insert (seg[x].first), S.insert (seg[x].second);
			
		if (S.size() == 3)
		{
			ans[red[0]] = '1';
			int p = seg[red[0]].x;
			
			for (auto [u, id] : g[p]) ans[id] = '0';
		}
	}
	
	for (int i = 1 ; i <= m ; i ++)
		cout << ans[i];
	cout << endl;
}
signed main()
{
	//	freopen("data.in","r",stdin);
	//	freopen("cfcode.out","w",stdout);
	std::ios::sync_with_stdio (false);
	std::cin.tie (nullptr);
	int t = 1;
	cin >> t;
	
	while (t--)
		solve();
		
	return 0;
}```

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值