首页 > 其他分享 >AGC001 题解

AGC001 题解

时间:2024-08-09 21:50:51浏览次数:11  
标签:10 AGC001 int 题解 ll Read num getchar

目录

A - BBQ Easy

先将 \(2N\) 个数排序,从大到小考虑,最大的数一定不会产生贡献,次大的数可以和最大的数捆绑在一起,并产生贡献,以此类推,这样的贪心正确性还是较为显然的。

#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll Read() {
	int sig = 1;
	ll num = 0;
	char c = getchar();
	while(!isdigit(c)) {
		if(c == '-') {
			sig = -1;
		}
		c = getchar();
	}
	while(isdigit(c)) {
		num = (num << 3) + (num << 1) + (c ^ 48);
		c = getchar();
	}
	return num * sig;
}
void Write(ll x) {
	if(x < 0) {
		putchar('-');
		x = -x;
	}
	if(x >= 10) {
		Write(x / 10);
	}
	putchar((x % 10) ^ 48);
}

const int N = 205;
int n, a[N];

int main() {
	int i;
	n = Read(), n <<= 1;
	for(i = 1; i <= n; i++) {
		a[i] = Read();
	}
	sort(a + 1, a + n + 1);
	int ans = 0;
	for(i = 1; i <= n; i += 2) {
		ans += a[i];
	}
	Write(ans), putchar('\n');
	return 0;
}

B - Mysterious Light

可以看到,从光反射第二次后开始后,以两轮为周期,光可能经过的范围总是为一个平行四边形,且光总是沿着平行四边形某个 \(120^\circ\) 的内角的角平分线射出。
比如样例的图:
image
设两条边长为 \(x, y\)。则对于一个平行四边形,只算它内部的光线总长,答案为:

\[f(x, y) = \begin{cases} f(y, x) & \text{if } x < y \\ f(x - y, y) + 2y & \text{otherwise.} \end{cases}\]

边界为 \(f(x, x) = x\)。
显然初始两条光线总长为 \(N\),则答案为 \(N + f(X, N - X)\),\(O(N)\) 暴力计算可拿 \(300\) 分。
观察这个式子,首先可以令边界为 \(f(x, 0) = -x\),可以证明两个边界是等价的,很像辗转相减法,可以优化为辗转相除法,即:

\[f(x, y) = \begin{cases} f(y, x) & \text{if } x < y \\ f(x \bmod y, y) + 2 \cdot \lfloor \frac{x}{y} \rfloor \cdot y & \text{otherwise.} \end{cases}\]

观察到当 \(x < y\) 时,下面的式子等价于上面的式子,可得:

\[f(x, y) = f(x \bmod y, y) + 2 \cdot \lfloor \frac{x}{y} \rfloor \cdot y \]

#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll Read() {
	int sig = 1;
	ll num = 0;
	char c = getchar();
	while(!isdigit(c)) {
		if(c == '-') {
			sig = -1;
		}
		c = getchar();
	}
	while(isdigit(c)) {
		num = (num << 3) + (num << 1) + (c ^ 48);
		c = getchar();
	}
	return num * sig;
}
void Write(ll x) {
	if(x < 0) {
		putchar('-');
		x = -x;
	}
	if(x >= 10) {
		Write(x / 10);
	}
	putchar((x % 10) ^ 48);
}

ll Solve(ll x, ll y) {
	return y ? Solve(y, x % y) + 2ll * (x / y) * y : -x;
}
int main() {
	ll n = Read(), x = Read();
	Write(n + Solve(n - x, x));
	return 0;
}

C - Shorten Diameter

没看数据范围,结果一看 \(N\) 只有 \(2000\)。
考虑暴力枚举直径的中心,对 \(K\) 的奇偶性进行分类讨论。

  • 当 \(K\) 为奇数时,枚举一条边,将与边的两个端点的距离最小值小于等于 \(\frac{K - 1}{2}\) 的点删去。
  • 当 \(K\) 为偶数时,枚举一个点,将与点的距离小于等于 \(\frac{K}{2}\) 的点删去。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll Read() {
	int sig = 1;
	ll num = 0;
	char c = getchar();
	while(!isdigit(c)) {
		if(c == '-') {
			sig = -1;
		}
		c = getchar();
	}
	while(isdigit(c)) {
		num = (num << 3) + (num << 1) + (c ^ 48);
		c = getchar();
	}
	return num * sig;
}
void Write(ll x) {
	if(x < 0) {
		putchar('-');
		x = -x;
	}
	if(x >= 10) {
		Write(x / 10);
	}
	putchar((x % 10) ^ 48);
}
const int N = 2005;
int n, cnt = 0, k, o;
vector<int> e[N];
bool vis[N];
void Dfs(int u, int dis) {
	vis[u] = true;
	if(dis > k / 2) {
		cnt++;
	}
	for(auto v : e[u]) {
		if(vis[v] || v == o) {
			continue;
		}
		Dfs(v, dis + 1);
	}
}
int main() {
	int i;
	n = Read(), k = Read();
	vector<pair<int, int> > vec;
	for(i = 1; i < n; i++) {
		int u = Read(), v = Read();
		vec.emplace_back(u, v);
		e[u].push_back(v), e[v].push_back(u);
	}
	int ans = INT_MAX;
	if(k & 1) {
		for(auto p : vec) {
			int u = p.first, v = p.second;
			memset(vis, 0, sizeof(vis)), cnt = 0;
			o = v, Dfs(u, 0), o = u, Dfs(v, 0);
			ans = min(ans, cnt);
		}
	}
	else {
		for(i = 1; i <= n; i++) {
			memset(vis, 0, sizeof(vis)), cnt = 0;
			Dfs(i, 0);
			ans = min(ans, cnt);
		}
	}
	Write(ans);
	return 0;
}

标签:10,AGC001,int,题解,ll,Read,num,getchar
From: https://www.cnblogs.com/IncludeZFR/p/18351561

相关文章

  • CF1999F.Expected Median 题解
    一.前言这是一道很有趣的数学题目,用到了逆元和组合数学,非常适合新手练手。二.题目大意:给出一个长度为\(n\)的\(01\)数组。找出所有长度为\(k\)的子序列的中位数,求出其和。妥妥的数学题~三.分析首先考虑对答案的贡献。很明显,只有\(1\)作为中位数时才会做出贡献,于是......
  • CF908G New Year and Original Order 题解
    CF908C定义\(S(n)\)为将\(n\)所有数位从小到大排序后得到的数,求\(\sum_{i=1}^{n}S(i)\)\(1\leqn\leq10^{700}\)看到这个题大部分人都会奔着数位\(dp\)的地方想但这个题的难度在于插入一个数后不好算贡献其实也挺好算的\(dp\)维护当前若干数字排完序......
  • CF641E Little Artem and Time Machine 题解
    题目传送门前置知识CDQ分治解法单点修改区间查询,但值域巨大,考虑离散化掉\(x\)。时刻\(t\)仍很大,考虑将其作为CDQ分治的第一维,然后套个CDQ分治即可,注意及时清空桶数组。代码CodeForces275382150#include<bits/stdc++.h>usingnamespacestd;#definelllonglon......
  • CF1209E2 Rotate Columns (hard version) 题解
    CF1209E2给定\(n\timesm\)的矩阵,可以对每一列进行若干次循环移位,求操作完成后每一行的最大值之和的最大值。\(1\leqn\leq12,1\leqm\leq2000\)这里\(m\)很大,但有一个很重要的性质这\(m\)列中只有最大的前\(n\)个会对答案产生贡献因此我们直接就把......
  • 【题解】ABC365(A~E)
    前四题30min切,然后T5死磕70min+几发小唐错,距离比赛结束还有16s交最后一发,AC了。目录A.LeapYear题目描述思路代码B.SecondBest题目描述思路代码C.TransportationExpenses题目描述思路代码D.AtCoderJanken3题目描述思路代码E.XorSigmaProblem题目描述思路代码A.Lea......
  • CF908E New Year and Entity Enumeration 题解
    CF908E给定\(m\),令\(M=2^m-1\)。给定\(\{0,1,\cdots,M\}\)的大小为\(n\)的子集\(T\),定义集合\(T\subseteqS\subseteq\{0,1,\cdots,M\}\)是好的当且仅当:\(a\inS\Rightarrowa\oplusM\inS\)\(a,b\inS\Rightarrowa\and\b\inS......
  • 题解:CF1209E1 Rotate Columns (easy version)
    题目传送门题意给出一个\(n\timesm\)的矩阵,我们可以对每一列进行循环位移,不限次数,最后求每一行的最大值之和。\(1\leqn\leq4,1\leqm\leq100\)思路注意到\(n\)的范围很小,那么我们也可以缩小\(m\)的范围。正确的方案显然是取整个矩阵的前\(n\)大值,并且将它......
  • CF1647F Madoka and Laziness 题解
    CF1647F给定排列\(p\),将其划分为两个单峰子序列,求两个单峰子序列的峰的组合的情况数。\(2\leqn\leq5\times10^5\)首先要注意到一个非常常见的地方:两个单峰子序列中的一个的峰值一定在整个排列\(p\)的最大值处这个非常显然,但并不注意到他的重要性,容易被忽视为......
  • 2024牛客暑期多校训练营8 I Haitang and Ranking 题解
    乱搞看到\(n=1e5\),时限3s,存在修改操作,很自然的想到根号分治。考虑按照时间分治。对每\(B\)个交换统一处理,\(B\)个交换最多有\(2B\)个元素改变状态,剩下都不变。那么只要对这\(2B\)元素内,暴力枚举,剩下的元素构建数据结构实现二维数点,平面内区间最值。因为\(a,b\)是不......
  • luogu题解:P10456 The Pilots Brothers' refrigerator【缺少 SPJ】
    思路此题题意酷似P10449.费解的开关。https://www.luogu.com.cn/problem/P10449不同之处便是状态连锁改变不同,但做法截然不同,此题是一个\(4\times4\)的矩阵。暴力枚举的复杂度是\(O(10^7)\),即\(2^{16}\times16\times16=16777216\),\(10^7\)的复杂度可以通......