AtCoder Beginner Contest 194 A~E题解

A - I Scream

题目大意

在日本,有如下四种冰淇淋产品:

  • 至少有 15 % 15\% 15%的milk solids和 8 % 8\% 8%的milk fat的产品称为“冰淇淋”;
  • 至少有 10 % 10\% 10%的milk solids和 3 % 3\% 3%的milk fat且不是冰淇淋的产品称为“冰奶”;
  • 至少有 3 % 3\% 3%的milk solids且不是冰淇淋或冰奶**的产品称为“乳冰”;
  • 不是以上三种的产品称为“调味冰”。

在这里,milk solids由milk fat和milk solids-not-fat组成。
有一种冰淇淋产品,它由 A % A\% A%的milk solids-not-fat和 B % B\% B%的milk fat组成。
这种产品是上述的哪一类?

0 ≤ A , B ≤ 100 0\le A,B\le 100 0A,B100
0 ≤ A + B ≤ 100 0\le A+B\le 100 0A+B100

输入格式

A   B A~B A B

输出格式

请按如下格式输出类别:

  • 如果这是冰淇淋,输出 1 1 1
  • 如果这是冰奶,输出 2 2 2
  • 如果这是乳冰,输出 3 3 3
  • 如果这是调味冰,输出 4 4 4

样例

A A A B B B输出
10 10 10 8 8 8 1 1 1
1 1 1 2 2 2 3 3 3
0 0 0 0 0 0 4 4 4

分析

只需将 A A A加上 B B B(变为milk solids的占比),再按题目所说的判断即可。

代码

#include <cstdio>
using namespace std;

int main()
{
	int a, b;
	scanf("%d%d", &a, &b);
	a += b;
	if(a >= 15 && b >= 8) puts("1");
	else if(a >= 10 && b >= 3) puts("2");
	else if(a >= 3) puts("3");
	else puts("4");
	return 0;
}

B - Job Assignment

题目大意

你的公司有 N N N位员工,他们叫员工 1 1 1,员工 2 2 2,……,员工 N N N
你有两份重要工作要完成——工作A和工作B。
员工 i i i可以在 A i A_i Ai分钟内完成工作A并在 B i B_i Bi分钟内完成工作B。
你要将两个工作分别分给某一位员工。
假设工作A分给了员工 i i i,工作B分给了员工 j j j,将要花的分钟数设为 t t t,则:
t = { A i + B i ( i = j ) max ⁡ { A i , B j } ( i ≠ j ) t= \begin{cases} A_i+B_i & (i=j) \\ \max\{A_i,B_j\} & (i\ne j) \\ \end{cases} t={Ai+Bimax{Ai,Bj}(i=j)(i=j)
求最小的 t t t

2 ≤ N ≤ 1000 2\le N\le 1000 2N1000
1 ≤ A i , B i ≤ 1 0 5 1\le A_i,B_i\le 10^5 1Ai,Bi105

输入格式

N N N
A 1   B 1 A_1~B_1 A1 B1
A 2   B 2 A_2~B_2 A2 B2
⋮ \vdots
A N   B N A_N~B_N AN BN

输出格式

输出答案。

样例

略,请自行前往AtCoder查看

分析

这题由于 N N N最大只有 1 0 3 10^3 103,所以枚举是完全可行的,只要枚举所有的 ( i , j ) (i,j) (i,j),再根据题目里的公式求出答案取最小值即可,这样做总时间复杂度为 O ( n 2 ) \mathcal O(n^2) O(n2)
另外,本题也有贪心的 O ( n ) \mathcal O(n) O(n)的算法,但是情况太多,代码太麻烦,所以这里不写。

代码

#include <cstdio>
#define maxn 1005
#define INF 2147483647
using namespace std;

int a[maxn], b[maxn];

inline void setmin(int& x, int y) { if(y < x) x = y; }
inline int max(int x, int y) { return x > y ? x : y; }

int main()
{
	int n;
	scanf("%d", &n);
	for(int i=0; i<n; i++)
		scanf("%d%d", a + i, b + i);
	int ans = INF;
	for(int i=0; i<n; i++)
	{
		setmin(ans, a[i] + b[i]); // i == j
		for(int j=i+1; j<n; j++)
		{
			setmin(ans, max(a[i], b[j]));
			setmin(ans, max(a[j], b[i]));
		}
	}
	printf("%d\n", ans);
	return 0;
}

C - Squared Error

题目大意

给你一个长度为 N N N的序列 A A A
输出 ∑ i = 2 N ∑ j = 1 i − 1 ( A i − A j ) 2 \displaystyle \sum_{i = 2}^{N} \sum_{j = 1}^{i - 1} (A_i - A_j)^2 i=2Nj=1i1(AiAj)2

2 ≤ N ≤ 3 × 1 0 5 2 \le N \le 3 \times 10^5 2N3×105
∣ A i ∣ ≤ 200 |A_i| \le 200 Ai200

输入格式

N N N
A 1   A 2   A 3   …   A N A_1~A_2~A_3~\dots~A_N A1 A2 A3  AN

输出格式

输出一行,即 ∑ i = 2 N ∑ j = 1 i − 1 ( A i − A j ) 2 \displaystyle \sum_{i = 2}^{N} \sum_{j = 1}^{i - 1} (A_i - A_j)^2 i=2Nj=1i1(AiAj)2

样例

样例输入1

3
2 8 4

样例输出1

56

通过计算,我们得到 ∑ i = 2 N ∑ j = 1 i − 1 ( A i − A j ) 2 = ( 8 − 2 ) 2 + ( 4 − 2 ) 2 + ( 4 − 8 ) 2 = 56 \displaystyle \sum_{i = 2}^{N} \sum_{j = 1}^{i - 1} (A_i - A_j)^2 = (8 - 2)^2 + (4 - 2) ^ 2 + (4 - 8) ^ 2 = 56 i=2Nj=1i1(AiAj)2=(82)2+(42)2+(48)2=56

样例输入2

5
-5 8 9 -4 -3

样例输出2

950

分析

根据公式 ( a − b ) 2 = a 2 + b 2 − 2 a b (a-b)^2=a^2+b^2-2ab (ab)2=a2+b22ab,我们可以使用如下推理:
∑ i = 2 N ∑ j = 1 i − 1 ( A i − A j ) 2 \sum_{i = 2}^{N} \sum_{j = 1}^{i - 1} (A_i - A_j)^2 i=2Nj=1i1(AiAj)2
∑ i = 2 N ∑ j = 1 i − 1 A i 2 + A j 2 − 2 A i A j \sum_{i = 2}^{N} \sum_{j = 1}^{i - 1} {A_i}^2+{A_j}^2-2A_iA_j i=2Nj=1i1Ai2+Aj22AiAj
( ∑ i = 2 N ∑ j = 1 i − 1 A i 2 ) + ( ∑ i = 2 N ∑ j = 1 i − 1 A j 2 ) − ( ∑ i = 2 N ∑ j = 1 i − 1 2 A i A j ) (\sum_{i = 2}^{N} \sum_{j = 1}^{i - 1} {A_i}^2)+(\sum_{i = 2}^{N} \sum_{j = 1}^{i - 1} {A_j}^2)-(\sum_{i = 2}^{N} \sum_{j = 1}^{i - 1} 2A_iA_j) (i=2Nj=1i1Ai2)+(i=2Nj=1i1Aj2)(i=2Nj=1i12AiAj)
这时,我们设 S i = ∑ j = 1 i − 1 A i S_i=\sum\limits_{j=1}^{i-1} A_i Si=j=1i1Ai,则:
( n − 1 ) ( ∑ i = 1 N A i 2 ) − 2 ( ∑ i = 1 N S i A i ) (n-1)(\sum_{i = 1}^{N} {A_i}^2)-2(\sum_{i = 1}^{N} S_iA_i) (n1)(i=1NAi2)2(i=1NSiAi)
这时,计算所有 S i S_i Si的时间复杂度为 O ( n ) \mathcal O(n) O(n),求最终结果的时间复杂度也是 O ( n ) \mathcal O(n) O(n),所以总时间复杂度为 O ( n ) \mathcal O(n) O(n)

代码

#include <cstdio>
#define maxn 300005
using namespace std;

using LL = long long;

int main()
{
	int n, s1 = 0;
	scanf("%d", &n);
	LL s2 = 0, m = 0LL;
	for(int i=0; i<n; i++)
	{
		LL x;
		scanf("%lld", &x);
		m += x * s1;
		s1 += x, s2 += x * x;
	}
	m <<= 1LL, s2 *= n - 1LL;
	printf("%lld\n", s2 - m);
	return 0;
}

D - Journey

题目大意

我们有一个 N N N个顶点(称为顶点 1 1 1、顶点 2 2 2、……、顶点 N N N)。
目前,这个图没有任何边。
Takahashi会重复执行以下操作,直到这个图变为连通图:

  • 从这 N N N个顶点中随机选一个顶点。每个顶点被抽中的概率相等,即 1 N \frac 1 N N1
  • 在现在站着的点和选中的顶点之间添加一条边,并走到这个点上。

求Takahashi执行操作次数的期望值。

输入格式

N N N

输出格式

输出答案,最大允许浮点数误差 1 0 − 6 10^{-6} 106

样例

N N N输出
2 2 2 2 2 2
3 3 3 4.5 4.5 4.5

分析

通过dp分析,我们可以得到 ∑ i = 1 n − 1 N i \sum\limits_{i=1}^{n-1}\frac Ni i=1n1iN这个公式。这时,就可以写代码了。

代码

#include <cstdio>
using namespace std;

int main()
{
	int n;
	scanf("%d", &n);
	double res = 0;
	for(int i=1; i<n; i++)
		res += double(n) / i;
	printf("%.8lf\n", res);
	return 0;
}

E - Mex Min

题目大意

我们定义 m e x ( x 1 , x 2 , x 3 , … , x k ) \mathrm{mex}(x_1, x_2, x_3, \dots, x_k) mex(x1,x2,x3,,xk)为最小的不出现在 x 1 , x 2 , x 3 , … , x k x_1, x_2, x_3, \dots, x_k x1,x2,x3,,xk中的自然数。
给你一个长度为 N N N的序列 A A A ( A 1 , A 2 , A 3 , … , A N ) (A_1, A_2, A_3, \dots, A_N) (A1,A2,A3,,AN)
对于每个 0 ≤ i ≤ N − M 0\le i\le N-M 0iNM的整数 i i i,我们计算 m e x ( A i + 1 , A i + 2 , A i + 3 , … , A i + M ) \mathrm{mex}(A_{i + 1}, A_{i + 2}, A_{i + 3}, \dots, A_{i + M}) mex(Ai+1,Ai+2,Ai+3,,Ai+M)。输出这些 N − M + 1 N-M+1 NM+1个结果中的最小值。

样例

略,请自行前往AtCoder查看

分析

先用最基本的方法想一下这道题,要求 m e x ( x 1 , x 2 , x 3 , … , x k ) \mathrm{mex}(x_1, x_2, x_3, \dots, x_k) mex(x1,x2,x3,,xk),只需记录每个 x i x_i xi的出现次数,放进数组 cnt \text{cnt} cnt里( cnt i = i \text{cnt}_i=i cnti=i x x x中出现的次数)。这时,只要找到 cnt \text{cnt} cnt中第一个 0 0 0即可,这样计算 m e x \mathrm{mex} mex的时间复杂度为 O ( k ) \mathcal O(k) O(k)。我们还可以想到一种优化方法,就是每一次计算 m e x ( A i + 1 , A i + 2 , A i + 3 , … , A i + M ) \mathrm{mex}(A_{i + 1}, A_{i + 2}, A_{i + 3}, \dots, A_{i + M}) mex(Ai+1,Ai+2,Ai+3,,Ai+M) 1 ≤ i ≤ N − M 1\le i\le N-M 1iNM)时,将 cnt A i \text{cnt}_{A_i} cntAi减少 1 1 1,并且将 cnt A i + M \text{cnt}_{A_{i+M}} cntAi+M增加 1 1 1,这样就达到了 O ( 1 ) \mathcal O(1) O(1)计算 cnt \text{cnt} cnt的效果。但是,即使这样还会TLE。所以,我们可以用一个set维护 cnt \text{cnt} cnt中所有 0 0 0的位置,这样总时间复杂度就能降至 O ( N log ⁡ M ) \mathcal O(N\log M) O(NlogM)

代码

这里注意,set中一定要添加 N N N

#include <cstdio>
#include <set>
#define maxn 1500005
using namespace std;

int cnt[maxn], a[maxn];

set<int> s;

inline void setmin(int& x, int y)
{
	if(y < x) x = y;
}

int main()
{
	int n, m;
	scanf("%d%d", &n, &m);
	for(int i=0; i<n; i++)
		scanf("%d", a + i);
	for(int i=0; i<m; i++)
		cnt[a[i]] ++;
	for(int i=0; i<n; i++)
		if(cnt[i] == 0)
			s.insert(i);
	s.insert(n);
	int ans = *s.begin();
	n -= m;
	for(int i=0; i<n; i++)
	{
		if(cnt[a[i + m]]++ == 0) s.erase(a[i + m]);
		if(--cnt[a[i]] == 0) s.insert(a[i]);
		setmin(ans, *s.begin());
	}
	printf("%d\n", ans);
	return 0;
}
AtCoder Beginner Contest 134 是一场 AtCoder 的入门级比赛,以下是每道题的简要题解: A - Dodecagon 题目描述:已知一个正十二边形的边长,求它的面积。 解题思路:正十二边形的内角为 $150^\circ$,因此可以将正十二边形拆分为 12 个等腰三角形,通过三角形面积公式计算面积即可。 B - Golden Apple 题目描述:有 $N$ 个苹果和 $D$ 个盘子,每个盘子最多可以装下 $2D+1$ 个苹果,求最少需要多少个盘子才能装下所有的苹果。 解题思路:每个盘子最多可以装下 $2D+1$ 个苹果,因此可以将苹果平均分配到每个盘子中,可以得到最少需要 $\lceil \frac{N}{2D+1} \rceil$ 个盘子。 C - Exception Handling 题目描述:给定一个长度为 $N$ 的整数序列 $a$,求除了第 $i$ 个数以外的最大值。 解题思路:可以使用两个变量 $m_1$ 和 $m_2$ 分别记录最大值和次大值。遍历整个序列,当当前数不是第 $i$ 个数时,更新最大值和次大值。因此,最后的结果应该是 $m_1$ 或 $m_2$ 中较小的一个。 D - Preparing Boxes 题目描述:有 $N$ 个盒子和 $M$ 个物品,第 $i$ 个盒子可以放入 $a_i$ 个物品,每个物品只能放在一个盒子中。现在需要将所有的物品放入盒子中,每次操作可以将一个盒子内的物品全部取出并分配到其他盒子中,求最少需要多少次操作才能完成任务。 解题思路:首先可以计算出所有盒子中物品的总数 $S$,然后判断是否存在一个盒子的物品数量大于 $\lceil \frac{S}{2} \rceil$,如果存在,则无法完成任务。否则,可以用贪心的思想,每次从物品数量最多的盒子中取出一个物品,放入物品数量最少的盒子中。因为每次操作都会使得物品数量最多的盒子的物品数量减少,而物品数量最少的盒子的物品数量不变或增加,因此这种贪心策略可以保证最少需要的操作次数最小。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值