AtCoder Beginner Contest 187 A~D题解

46 篇文章 7 订阅
43 篇文章 5 订阅

A - Large Digits

题目大意

给定两个三位整数 A A A B B B,求它们数位和的最大值。
数位和:例如, 123 123 123的数位和是 1 + 2 + 3 = 6 1+2+3=6 1+2+3=6
100 ≤ A , B ≤ 999 100 \le A,B \le 999 100A,B999

输入格式

A    B A~~B A  B

输出格式

一行,即 A A A B B B数位和的最大值。

样例

输入输出
123 2349
593 95317
100 99927

分析

直接按题目照做即可。

代码

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

int main(int argc, char** argv)
{
	char a[10], b[10];
	scanf("%s%s", a, b);
	int as = 0, bs = 0;
	for(int i=0; a[i]; i++)
		as += a[i] - '0';
	for(int i=0; b[i]; i++)
		bs += b[i] - '0';
	printf("%d\n", max(as, bs));
	return 0;
}

B - Gentle Pairs

题目大意

N N N个点,每个点的坐标是 ( x i , y i ) (x_i,y_i) (xi,yi) x x x坐标互不相同。
有多少对符合“ − 1 ≤ 斜率 ≤ 1 -1\le斜率\le1 1斜率1”的点?
1 ≤ N ≤ 1 0 3 1\le N\le 10^3 1N103
∣ x i ∣ , ∣ y i ∣ ≤ 1 0 3 |x_i|,|y_i|\le 10^3 xi,yi103
x i ≠ x j x_i \ne x_j xi=xj ( i < j i < j i<j)

输入格式

N N N
x 1   y 1 x_1~y_1 x1 y1
⋮ \vdots
x n   y n x_n~y_n xn yn

输出格式

输出答案。

样例

样例输入1

3
0 0
1 2
2 1

样例输出1

2

有三个点 ( 0 , 0 ) (0,0) (0,0) ( 1 , 2 ) (1,2) (1,2) ( 2 , 1 ) (2,1) (2,1)

  • ( 0 , 0 ) (0,0) (0,0) ( 1 , 2 ) (1,2) (1,2),斜率为 2 2 2
  • ( 0 , 0 ) (0,0) (0,0) ( 2 , 1 ) (2,1) (2,1),斜率为 1 2 \frac12 21
  • ( 1 , 2 ) (1,2) (1,2) ( 2 , 1 ) (2,1) (2,1),斜率为 − 1 -1 1

2 2 2对符合条件的点。

样例输入2

1
-691 273

样例输出2

0

只有 1 1 1个点,无法组成对,输出 0 0 0

样例输入3

10
-31 -35
8 -36
22 64
5 73
-14 8
18 -58
-41 -85
1 -88
-21 -85
-11 82

样例输出3

11

分析

( x 1 , y 1 ) (x_1,y_1) (x1,y1) ( x 2 , y 2 ) (x_2,y_2) (x2,y2)的斜率是 y 1 − y 2 x 1 − x 2 \frac{y_1-y_2}{x1-x2} x1x2y1y2
推理过程:
− 1 ≤ y 1 − y 2 x 1 − x 2 ≤ 1 -1 \le \frac{y_1-y_2}{x_1-x_2} \le 1 1x1x2y1y21
∣ y 1 − y 2 x 1 − x 2 ∣ ≤ 1 |\frac{y_1-y_2}{x_1-x_2}| \le 1 x1x2y1y21
∣ y 1 − y 2 ∣ ∣ x 1 − x 2 ∣ ≤ 1 \frac{|y_1-y_2|}{|x_1-x_2|}\le 1 x1x2y1y21
为了防止浮点数精度误差,我们继续:
∣ y 1 − y 2 ∣ ≤ ∣ x 1 − x 2 ∣ |y_1-y_2|\le|x1-x2| y1y2x1x2∣
这时,就可以写代码了。

代码

枚举所有对点即可。

#include <cstdio>
#include <cmath>
#define maxn 1005
using namespace std;
 
int x[maxn], y[maxn];
 
inline bool slope_check(int x1, int y1, int x2, int y2)
{
	int dx = abs(x1 - x2), dy = abs(y1 - y2);
	return dy <= dx;
}
 
int main(int argc, char** argv)
{
	int n, cnt = 0;
	scanf("%d", &n);
	for(int i=0; i<n; i++)
		scanf("%d%d", x + i, y + i);
	for(int i=0; i<n-1; i++)
		for(int j=i+1; j<n; j++)
			if(slope_check(x[i], y[i], x[j], y[j]))
				cnt ++;
	printf("%d\n", cnt);
	return 0;
}

C - 1-SAT

题目大意

给你 N N N个字符串 S 1 , S 2 , . . . , S N S_1,S_2,...,S_N S1,S2,...,SN。每个字符串都由小写字母组成,前面有至多 1 1 1!
找到 S 1 , S 2 , . . . , S N S_1,S_2,...,S_N S1,S2,...,SN中任意一个字符串,使 S S S中出现了“!+这个字符串”(没有引号)。如果没有符合条件的字符串,输出satisfiable
1 ≤ N ≤ 1 0 5 1\le N\le 10^5 1N105
1 ≤ ∣ S i ∣ ≤ 10 1\le |S_i|\le 10 1Si10

输入格式

N N N
S 1 S_1 S1
⋮ \vdots
S N S_N SN

输出格式

如果有符合条件的字符串,输出任意一个;
否则,输出satisfiable

样例

样例输入1

6
a
!a
b
!c
d
!d

样例输出1

a

S 1 S_1 S1a S 2 S_2 S2!a,所以 S 1 S_1 S1符合条件;
S 5 S_5 S5d S 6 S_6 S6!d,所以 S 5 S_5 S5也符合条件,输出d也会被判为正确。

样例输入2

10
red
red
red
!orange
yellow
!blue
cyan
!green
brown
!gray

样例输出2

satisfiable

没有符合条件的字符串。

分析

如果暴力去枚举两个字符串(如,a!a),需要两重循环,复杂度为 O ( N 2 ) \mathcal O(N^2) O(N2)(由于字符串太短可以忽略字符串比较),这里 N N N最大为 1 0 5 10^5 105,所以,枚举法不可用。
我们再考虑 O ( n log ⁡ n ) \mathcal O(n\log n) O(nlogn)
可以每次输入字符串时判断一下,如果它以!开头将它的!后面的内容放入set中,否则将整个字符串放入vector中。最后,循环遍历vector O ( n ) \mathcal O(n) O(n)),每次在set中查找这个字符串( O ( log ⁡ n ) \mathcal O(\log n) O(logn))。总时间复杂度为 O ( n log ⁡ n ) \mathcal O(n\log n) O(nlogn)

代码

#include <iostream>
#include <set>
#include <string>
#include <vector>
using namespace std;

vector<string> v;
set<string> s;

int main(int argc, char** argv)
{
	ios::sync_with_stdio(false); cin.tie(0);
	int n;
	cin >> n;
	while(n--)
	{
		string x;
		cin >> x;
		if(x[0] == '!')
			s.insert(x.substr(1));
		else v.push_back(x);
	}
	for(int i=0; i<v.size(); i++)
		if(s.find(v[i]) != s.end())
		{
			cout << v[i] << endl;
			return 0;
		}
	cout << "satisfiable\n";
	return 0;
}

D - Choose Me

题目大意

略,请自行前往AtCoder查看。
数据范围:
1 ≤ N ≤ 1 0 5 1\le N\le 10^5 1N105
1 ≤ A i , B i ≤ 1 0 9 1\le A_i,B_i\le 10^9 1Ai,Bi109

输入格式

N N N
A 1   B 1 A_1~B_1 A1 B1
⋮ \vdots
A N   B N A_N~B_N AN BN

输出格式

输出答案。

样例

样例输入1

4
2 1
2 2
5 1
1 3

样例输出1

1

Takahashi在第三个城市演讲后,AokiTakahashi将分别得到 5 5 5 6 6 6个投票。

样例输入2

5
2 1
2 1
2 1
2 1
2 1

样例输出2

3

在任意三个城市演讲后,AokiTakahashi将分别得到 4 4 4 9 9 9个投票。

样例输入3

1
273 691

样例输出3

1

分析

换句话说,我们的目的就是使得AokiTakahashi的票数差距逐渐减少。
最开始,票数的差距是Aoki票数的和,也就是 ∑ i = 1 n A i \sum\limits_{i=1}^nA_i i=1nAi
每去第 i i i个城市,差距减少 2 A i + B i 2A_i+B_i 2Ai+Bi,因此,我们可以贪心地先前往差距减少多的城市。这一点可以用数组+排序setpriority_queue三种方法实现(我选择的是priority_queuesetpriority_queue更快一些)。

代码

注意:一定不能忘记使用long long!!!

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

typedef long long LL;

priority_queue<LL> q;

int main(int argc, char** argv)
{
	int n;
	scanf("%d", &n);
	LL diff = 0;
	while(n--)
	{
		LL ao, ta;
		scanf("%lld%lld", &ao, &ta);
		diff += ao;
		q.push(ao + ao + ta);
	}
	int ans = 0;
	while(!q.empty())
	{
		ans ++;
		if((diff -= q.top()) < 0)
		{
			printf("%d\n", ans);
			return 0;
		}
		q.pop();
	}
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值