AtCoder Beginner Contest 188 A~D题解

A - Three-Point Shot

有两个球队,分别得到 X X X分和 Y Y Y分,问得分较少的球队能否在获得三分后超越对方。

0 ≤ X , Y ≤ 100 0\le X,Y\le 100 0X,Y100
X ≠ Y X \ne Y X=Y
X X X Y Y Y都是整数。

输入格式

X   Y X~Y X Y

输出格式

如果能,输出Yes;否则,输出No

样例

X Y 输出
3 5 Yes

分析

这个不用说了吧,就是求两个数的差是否小于 3 3 3……

代码

#include <cstdio>
#include <algorithm>
using namespace std;

int main(int argc, char** argv)
{
    
    
	int a, b;
	scanf("%d%d", &a, &b);
	puts((abs(a - b) < 3)? "Yes": "No");
	return 0;
}

B - Orthogonality

题目大意

给定两个长度为 N N N的数组 A = { A 1 , A 2 , A 3 , . . . , A N } A=\{A_1,A_2,A_3,...,A_N\} A={ A1,A2,A3,...,AN} B = { B 1 , B 2 , B 3 , . . . , B N } B=\{B_1,B_2,B_3,...,B_N\} B={ B1,B2,B3,...,BN}。请判定 A A A B B B的内项积是否为 0 0 0。换句话说,判断 ∑ i = 1 N A i B i \sum\limits_{i=1}^NA_iB_i i=1NAiBi是否为 0 0 0

1 ≤ N ≤ 1 0 5 1\le N\le 10^5 1N105
− 100 ≤ A i , B i ≤ 100 -100\le A_i,B_i\le 100 100Ai,Bi100 注意:可能会出现负数!

输入格式

N N N
A 1   A 2   A 3   …   A N A_1~A_2~A_3~\dots~A_N A1 A2 A3  AN
B 1   B 2   B 3   …   B N B_1~B_2~B_3~\dots~B_N B1 B2 B3  BN

输出格式

如果 A A A B B B的内项积为 0 0 0,输出Yes;否则,输出No

样例

样例输入1

2
-3 6
4 2

样例输出1

Yes

N = 2 N = 2 N=2
A = { − 3 , 6 } A = \{-3,6\} A={ 3,6}
B = { 4 , 2 } B = \{4,2\} B={ 4,2}
A A A B B B的内项积为: ∑ i = 1 N A i B i = ( − 3 ) × 4 + 6 × 2 = 0 \sum\limits_{i=1}^NA_iB_i = (-3)\times4+6\times2=0 i=1NAiBi=(3)×4+6×2=0,所以输出Yes

样例输入2

2
4 5
-1 -3

样例输出2

No

N = 2 N = 2 N=2
A = { 4 , 5 } A = \{4,5\} A={ 4,5}
B = { − 1 , − 3 } B = \{-1,-3\} B={ 1,3}
A A A B B B的内项积为: ∑ i = 1 N A i B i = 4 × ( − 1 ) + 5 × ( − 3 ) = 19 \sum\limits_{i=1}^NA_iB_i = 4\times(-1)+5\times(-3)=19 i=1NAiBi=4×(1)+5×(3)=19,所以输出No

样例输入3

3
1 3 5
3 -6 3

样例输出3

Yes

N = 3 N = 3 N=3
A = { 1 , 3 , 5 } A = \{1,3,5\} A={ 1,3,5}
B = { 3 , − 6 , 3 } B = \{3,-6,3\} B={ 3,6,3}
A A A B B B的内项积为: ∑ i = 1 N A i B i = 1 × 3 + 3 × ( − 6 ) + 5 × 3 = 0 \sum\limits_{i=1}^NA_iB_i = 1\times3+3\times(-6)+5\times3=0 i=1NAiBi=1×3+3×(6)+5×3=0,所以输出Yes

分析

只需按题目说的照做即可。

代码

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

int a[maxn];

int main(int argc, char** argv)
{
    
    
	int n;
	scanf("%d", &n);
	for(int i=0; i<n; i++)
		scanf("%d", a + i);
	int res = 0;
	for(int i=0; i<n; i++)
	{
    
    
		int x;
		scanf("%d", &x);
		res += x * a[i];
	}
	puts(res == 0? "Yes": "No");
	return 0;
}

C - ABC Tournament

题目大意

2 N 2^N 2N个玩家,每个玩家的编号是 i i i且有一个排名 A i A_i Ai,举行 N N N场淘汰赛。
淘汰赛可以看作一棵二叉树,制度如下:
如, N = 3 N=3 N=3,有 8 8 8个玩家,排名分别为 1 , 6 , 7 , 10 , 5 , 13 , 8 , 9 1,6,7,10,5,13,8,9 1,6,7,10,5,13,8,9

  1. 1,6,7,10,5,13,8,9 两两比较,淘汰1,7,5,8;(排名越高的玩家越厉害)
  2. 6,10,13,9 两两比较,淘汰6,9;
  3. 10,13 13 13 13最大,胜利!

请输出比赛的第二名(即在最后一轮被淘汰的玩家,如上面的 13 13 13)的编号。

1 ≤ N ≤ 16 1\le N\le 16 1N16
1 ≤ A i ≤ 1 0 9 1\le A_i \le 10^9 1Ai109
A i A_i Ai互不相同。

输入格式

N N N
A 1   A 2   A 3   …   A 2 N A_1~A_2~A_3~\dots~A_{2^N} A1 A2 A3  A2N

输出格式

输出最终获得第二名的玩家的编号

样例

样例输入1

2
1 4 2 5

样例输出1

2

4 4 4个玩家,排名分别为 1 , 4 , 2 , 5 1,4,2,5 1,4,2,5

  1. 1,4,2,5
  2. 4,5( 2 2 2号玩家在这里被淘汰了)

所以,我们输出 2 2 2

样例输入2

2
3 1 5 4

样例输出2

1

4 4 4个玩家,排名分别为 3 , 1 , 5 , 4 3,1,5,4 3,1,5,4

  1. 3,1,5,4
  2. 3,5( 1 1 1号玩家在这里被淘汰了)

所以,我们输出 1 1 1

样例输入3

4
6 13 12 5 3 7 10 11 16 9 8 15 2 1 14 4

样例输出3

2

博主提示:在这个样例上手算,就可以知道不能将输入排序后取第二大的值!!!

分析

首先,题目不允许偷懒(要求第二名的编号),不能将输入排序后取第二大的值
我们考虑别的方法。
很容易想到,可以直接模拟。不过,模拟时不能直接删除元素,会TLE。可以采取利用循环队列的 O ( 1 ) \mathcal O(1) O(1)进出,每次出队两个元素,再将其中较大的再放入队列即可。最后,当队列中只剩两个元素时,输出其中较小的编号即可。

代码

写代码时要注意两点:

  1. 一定要使用long long
  2. 要在进行队列操作时记录编号,可以用pair实现。

注:这段代码的第19行使用了C++11的新特性,请使用C++>=11编译器运行!(若无法运行请改为q.push(pli(x, i));

#include <cstdio>
#include <queue>
#include <vector> // pair
using namespace std;

typedef long long LL;
typedef pair<LL, int> pli;

int main(int argc, char** argv)
{
    
    
	queue<pli> q;
	int n;
	scanf("%d", &n);
	n = 1 << n;
	for(int i=1; i<=n; i++)
	{
    
    
		LL x;
		scanf("%lld", &x);
		q.emplace(x, i);
	}
	while(q.size() > 2)
	{
    
    
		int times = q.size() / 2;
		for(int i=0; i<times; i++)
		{
    
    
			pli x = q.front(); q.pop();
			pli y = q.front(); q.pop();
			if(x.first < y.first) q.push(y);
			else q.push(x);
		}
	}
	pli x = q.front(); q.pop();
	pli y = q.front(); q.pop();
	printf("%d\n", x.first < y.first? x.second: y.second);
	return 0;
}

D - Snuke Prime

题目大意

Takahashi需要使用 N N N种服务。
每种服务的价格是 c i c_i ci元(原题中钱币单位是日元,翻译时使用人民币作单位),他需要从第 a i a_i ai天的开始(0:00)用到第 b i b_i bi天的结束(23:59)。有一种特殊的服务,它可以使你无限次使用任意其它服务,每天收费 C C C元(需要从一天的开始订阅到一天的结束,订阅结束时失效,可以多次订阅)。
Takahashi使用这些服务至少需要多少元?

1 ≤ N ≤ 2 × 1 0 5 1\le N\le 2\times 10^5 1N2×105
1 ≤ C ≤ 1 0 9 1\le C\le 10^9 1C109
1 ≤ a i ≤ b i ≤ 1 0 9 1\le a_i\le b_i\le 10^9 1aibi109
1 ≤ c i ≤ 1 0 9 1\le c_i\le 10^9 1ci109

输入格式

N   C N~C N C
a 1   b 1   c 1 a_1~b_1~c_1 a1 b1 c1
a 2   b 2   c 2 a_2~b_2~c_2 a2 b2 c2
. . . ... ...
a N   b N   c N a_N~b_N~c_N aN bN cN

输出格式

输出一行,即最少需要的钱数。

样例

样例输入1

2 6
1 2 4
2 2 4

样例输出1

10

sample1_note

样例输入2

5 1000000000
583563238 820642330 44577
136809000 653199778 90962
54601291 785892285 50554
5797762 453599267 65697
468677897 916692569 87409

样例输出2

163089627821228

最优方案是不订阅特殊服务。

样例输入3

5 100000
583563238 820642330 44577
136809000 653199778 90962
54601291 785892285 50554
5797762 453599267 65697
468677897 916692569 87409

样例输出3

88206004785464

自制样例

博主在这里再提供一组样例,方便手算后面的代码以及理解题目的意思。

输入:

2 7
1 3 5
2 6 4

输出:

31

在这组数据中,我们在第 2 2 2 3 3 3天订阅特殊服务。

分析

参考:AtCoder官方题解
我们可以把每一个服务的订阅拆分成两个事件 ( a i − 1 , c i ) (a_i-1,c_i) (ai1,ci) ( b i , − c i ) (b_i,-c_i) (bi,ci)。每个事件有两个参数,分别是时间(某一天的最后一刻)和每天增加的钱数(可以为负数,表示减少需要花的钱)。然后,再按时间排序这些事件。
我们可以用变量fee记录每天需要花的钱,用ans记录答案。循环遍历每个事件,当这个事件的事件与上一次不同时,将ans加上计算最划算的付钱方法(分开付,要花fee元或一起付,花 C C C元)乘以与上一次差的天数,最后加上当前事件的增加钱数。
最后,输出ans即可。

代码

作为一个优先队列爱好者,排序当然是用priority_queue实现了~
以下代码要注意三点:

  • 必须使用long long
  • 建议使用pair存储;
  • 拆分事件时第一个事件 ( a i − 1 , c i ) (a_i-1,c_i) (ai1,ci)中的 a i a_i ai一定不能忘记 − 1 -1 1(因为 a i a_i ai表示的是一天的开始,应该转换为前一天的结束)。
#include <cstdio>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;

typedef long long LL;
typedef pair<LL, LL> pll;

int main(int argc, char** argv)
{
    
    
	int n;
	LL c;
	scanf("%d%lld", &n, &c);
	priority_queue<pll, vector<pll>, greater<pll> > q;
	while(n--)
	{
    
    
		LL x, y, z;
		scanf("%lld%lld%lld", &x, &y, &z);
		q.emplace(--x, z);
		q.emplace(y, -z);
	}
	LL ans = 0LL, fee = 0LL, last = 0LL;
	while(!q.empty())
	{
    
    
		auto [day, cost] = q.top(); q.pop();
		if(last != day)
		{
    
    
			ans += min(c, fee) * (day - last);
			last = day;
		}
		fee += cost;
	}
	printf("%lld\n", ans);
	return 0;
}

上面的代码使用了C++17新特性,如果上面的代码无法通过本地编译,请使用下面的代码:

#include <cstdio>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;

typedef long long LL;
typedef pair<LL, LL> pll;

int main(int argc, char** argv)
{
    
    
	int n;
	LL c;
	scanf("%d%lld", &n, &c);
	priority_queue<pll, vector<pll>, greater<pll> > q;
	while(n--)
	{
    
    
		LL x, y, z;
		scanf("%lld%lld%lld", &x, &y, &z);
		q.push(pll(--x, z));
		q.push(pll(y, -z));
	}
	LL ans = 0LL, fee = 0LL, last = 0LL;
	while(!q.empty())
	{
    
    
		LL day = q.top().first, cost = q.top().second; q.pop();
		if(last != day)
		{
    
    
			ans += min(c, fee) * (day - last);
			last = day;
		}
		fee += cost;
	}
	printf("%lld\n", ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/write_1m_lines/article/details/112555508
今日推荐