Codeforces Round #629 (Div. 3)

https://codeforces.com/contest/1328


A - Divisibility Problem

记得取模

#include 
#define ll long long
#define sc scanf
#define pr printf
using namespace std;
const int MAXN = 2e5 + 5;
int main()
{
	int T = 1;
	sc("%d", &T);
	while (T--)
	{
		ll a, b;
		sc("%lld%lld", &a, &b);
		pr("%lld\n", (b - a % b) % b);
	}
}

B - K-th Beautiful String

假设这个位置放 a ,看看后面有多少种方法,就是组合数

#include 
#define ll long long
#define sc scanf
#define pr printf
using namespace std;
const int MAXN = 2e5 + 5;
 
int main()
{
	int T = 1;
	sc("%d", &T);
	while (T--)
	{
		ll n, k;
		sc("%lld%lld", &n, &k);
		k--;
		ll a = n - 2, b = 2;
		for (int i = 1; i <= n; i++)
		{
			ll ans = 0;
			if (b == 2)
				ans = (a - 1 + b) * (a - 1 + b - 1) / 2;
			else
				ans = a;
			if (ans > k && a != 0)
			{
				pr("a");
				a--;
			}
			else
			{
				k -= ans;
				pr("b");
				b--;
			}
		}
		pr("\n");
	}
}

C - Ternary XOR

遍历,遇到 0 2 平分,遇到 1 将 1 给第一个,后面全给第二个数字

#include 
#define ll long long
#define sc scanf
#define pr printf
using namespace std;
const int MAXN = 2e5 + 5;
char s[MAXN];
char q[MAXN], w[MAXN];
int main()
{
	int T = 1;
	sc("%d", &T);
	while (T--)
	{
		sc("%*d");
		sc("%s", s);
		int len = strlen(s);
		int cnt1 = 0, cnt2 = 0;
		for (int i = 0; i < len; i++)
		{
			if (s[i] == '2')
			{
				q[cnt1++] = '1';
				w[cnt2++] = '1';
			}
			else if (s[i] == '0')
			{
				q[cnt1++] = '0';
				w[cnt2++] = '0';
			}
			else
			{
				q[cnt1++] = '1';
				w[cnt2++] = '0';
				while (cnt1 < len)
					q[cnt1++] = '0';
				while (cnt2 < len)
				{
					w[cnt2] = s[cnt2];
					cnt2++;
				}
				break;
			}
		}
		q[cnt1] = '\0';
		w[cnt2] = '\0';
		pr("%s\n%s\n", q, w);
	}
}

D - Carousel

n 个数字组成一个圈,相邻的不同的数字不可用相同的颜色,求最少颜色

如果存在相邻并且相同的数字,答案是1 或者 2

判掉 1 的情况,剩下的 2 的情况,从他们中间断开填入颜色 1 2 1 2 填即可。

如果不存在相邻的数字,分奇偶,偶数直接 1 2 1 2 填入颜色即可,奇数,需要三种,随便一个3 ,剩下的 1 2 1 2

比赛时犯了一个傻逼错误,然后卡题了,然后后面的题都不想看了(反正unrate)

 

#include 
#define ll long long
#define sc scanf
#define pr printf
using namespace std;
const int MAXN = 2e5 + 5;
int a[MAXN];
int ans[MAXN];
int main()
{
	int T = 1;
	sc("%d", &T);
	for (int l = 1; l <= T; l++)
	{
		int n;
		sc("%d", &n);
		for (int i = 1; i <= n; i++)
		{
			sc("%d", &a[i]);
		}
		if (n == 1)
		{
			pr("1\n1\n");
			continue;
		}
		int f = 0;
		for (int i = 1; i <= n; i++)
		{
			if (i == n)
			{
				if (a[i] == a[1])
				{
					f = n;
					break;
				}
			}
			else if (a[i] == a[i + 1])
			{
				f = i;
				break;
			}
		}
		if (f == 0)
		{
			if (n % 2 == 0)
			{
				pr("2\n");
				for (int i = 1; i <= n; i++)
				{
					if (i & 1)
						pr("1 ");
					else
						pr("2 ");
				}
				pr("\n");
			}
			else
			{
				pr("3\n");
				for (int i = 1; i < n; i++)
				{
					if (i & 1)
						pr("1 ");
					else
						pr("2 ");
				}
				pr("3 ");
				pr("\n");
			}
		}
		else
		{
			for (int i = 2; i <= n; i++)
			{
				if (a[i] != a[1])
				{
					pr("2\n");
 
					if (n % 2 == 0)
					{
						ans[f] = 1;
						if (f + 1 <= n)
							ans[f + 1] = 2;
						else
							ans[1] = 2;
					}
					else
					{
						ans[f] = 1;
						if (f + 1 <= n)
							ans[f + 1] = 1;
						else
							ans[1] = 1;
					}
					int t = f - 1;
					while (t >= 1)
					{
						ans[t] = 3 - ans[t + 1];
						t--;
					}
					t = f + 2;
					while (t <= n)
					{
						ans[t] = 3 - ans[t - 1];
						t++;
					}
					for (int i = 1; i <= n; i++)
						pr("%d ", ans[i]);
 
					pr("\n");
					goto qwe;
				}
			}
			pr("1\n");
			for (int i = 1; i <= n; i++)
				pr("1 ");
			pr("\n");
		}
	qwe:;
	}
}

E - Tree Queries

给你一棵树,每次询问若干个点,问是否存在一条从 1 开始的链,使得这些点距离链的距离小于等于 1 

从根节点开始的链,距离小于等于1,考虑将所有点变成他的爸爸,然后就变成了这个这些点是否在一条链上,然后倍增lCA即可

由于我不会倍增LCA,但我会树剖。

#include 
#define ll long long
#define sc scanf
#define pr printf
using namespace std;
const int MAXN = 2e5 + 5;
struct edge
{
	int to;
	int nex;
}e[MAXN * 2];
int head[MAXN], tot;
int son[MAXN], fa[MAXN], dep[MAXN], sz[MAXN];
int p[MAXN], fp[MAXN], top[MAXN], pos;
void init()
{
	memset(head, -1, sizeof(head));
	tot = 1;
	memset(son, -1, sizeof(son));
	pos = 1;
}
void add(int a, int b)
{
	e[tot] = edge{ b,head[a] };
	head[a] = tot++;
}
void dfs1(int u, int f)
{
	fa[u] = f;
	dep[u] = dep[f] + 1;
	sz[u] = 1;
	for (int i = head[u]; i + 1; i = e[i].nex)
	{
		int v = e[i].to;
		if (v == f)
			continue;
		dfs1(v, u);
		sz[u] += sz[v];
		if (son[u] == -1 || (sz[son[u]] <= sz[v]))
			son[u] = v;
	}
}
void dfs2(int u, int tp)
{
	top[u] = tp;
	p[u] = pos;
	fp[pos] = u;
	pos++;
	if (son[u] == -1)
		return;
	dfs2(son[u], tp);
	for (int i = head[u]; i + 1; i = e[i].nex)
	{
		int v = e[i].to;
		if (v == fa[u] || v == son[u])
			continue;
		dfs2(v, v);
	}
}
int lca(int a, int b)
{
	int t1 = top[a];
	int t2 = top[b];
	while (t1 != t2)
	{
		if (dep[t1] < dep[t2])
		{
			swap(t1, t2);
			swap(a, b);
		}
		a = fa[t1];
		t1 = top[a];
		//
	}
	if (dep[a] < dep[b])
		return a;
	else
		return b;
}
int main()
{
	init();
	int n, m;
	sc("%d%d", &n, &m);
	for (int i = 1; i < n; i++)
	{
		int a, b;
		sc("%d%d", &a, &b);
		add(a, b);
		add(b, a);
	}
	dfs1(1, 0);
	dfs2(1, 1);
	while (m--)
	{
		int num, t;
		sc("%d", &num);
		vectorv;
		for (int i = 0; i < num; i++)
		{
			sc("%d", &t);
			if (t != 1)
				v.push_back(fa[t]);
		}
		sort(v.begin(), v.end(), [](int q, int w) {
			return dep[q] > dep[w];
			});
		num = v.size();
		for (int i = 0; i < num - 1; i++)
		{
			int t = lca(v[i], v[i + 1]);
			if (t != v[i + 1])
			{
				pr("NO\n");
				goto qwe;
			}
		}
		pr("YES\n");
	qwe:;
	}
}

F - Make k Equal

给你 n 个数字,每次可以选择一个最大的数字-1,或者最小的数字+1,问最少操作多少次使得有 k 个数字相等。

就是只考虑从左往右,然后只考虑从右往左,最后考虑两个都取的情况,就是将多余的放回左边或者右边。

记得先判不需要移动的情况,不然后面可能会出现负数。

在两个都取的情况,只能将多余的放回左边-1或者右边+1,因为我们在这种情况下考虑的是两部分都对 k个相等 产生贡献。

#include 
#define ll long long
#define sc scanf
#define pr printf
using namespace std;
const int MAXN = 2e5 + 5;
ll a[MAXN];
ll num[MAXN];
#define Pair pair//第一个值是个数,第二个值是花费
Pair val1[MAXN], val2[MAXN];
ll t[MAXN];
int main()
{
	int n, k;
	sc("%d%d", &n, &k);
	for (int i = 1; i <= n; i++)
	{
		sc("%lld", &a[i]);
		t[i] = a[i];
	}
	sort(t + 1, t + 1 + n);
	int qq = unique(t + 1, t + 1 + n) - (t + 1);
	for (int i = 1; i <= n; i++)
	{
		a[i] = lower_bound(t + 1, t + 1 + qq, a[i]) - t;
		num[a[i]]++;
	}
	for (int i = 1; i <= qq; i++)
	{
		if (num[i] >= k)
		{
			pr("0\n");
			return 0;
		}
	}
	ll ans = 1e18;
	for (int i = 1; i <= qq; i++)
	{
		val1[i].first = val1[i - 1].first + num[i];
		val1[i].second = val1[i - 1].first * (t[i] - t[i - 1]) + val1[i - 1].second;
		if (val1[i].first >= k)
			ans = min(ans, val1[i].second - (val1[i].first - k));
	}
	for (int i = qq; i >= 1; i--)
	{
		val2[i].first = val2[i + 1].first + num[i];
		val2[i].second = val2[i + 1].first * (t[i + 1] - t[i]) + val2[i + 1].second;
		if (val2[i].first >= k)
			ans = min(ans, val2[i].second - (val2[i].first - k));
	}
	for (int i = 1; i <= qq; i++)
		if (val1[i].first + val2[i].first - num[i] >= k)
			ans = min(ans, val1[i].second + val2[i].second - (val1[i].first + val2[i].first - num[i] - k));
	pr("%lld\n", ans);
}

 

你可能感兴趣的:(codeforces)