T1-三角形的分类
题目描述
给定三个角度 a a a, b b b 及 c c c。请判断这三个角在平面上能组成什么样的三角形:
∘
\circ
∘ 如果不能组成三角形,输出 Error
∘
\circ
∘ 如果能组成等边三角形,输出 Equilateral
∘
\circ
∘ 如果能组成等腰直角三角形,输出 Isosceles right
∘
\circ
∘ 如果能组成等腰三角形,输出 Isosceles
∘
\circ
∘ 如果能组成直角三角形,输出 Right
∘
\circ
∘ 如果能组成不等边三角形,输出 Scalene
输入格式
第一行:第一个角的角度 a
第二行:第二个角的角度 b
第三行:第三个角的角度 c
输出格式
根据题目要求输出对应的文字
数据范围
1 ≤ a , b , c ≤ 180 1\leq a,b,c\leq 180 1≤a,b,c≤180
样例输入
60
60
60
样例输出
Equilateral
分析
这题只需要用 if 判断一下就行了。
代码
#include <bits/stdc++.h>
using namespace std;
int a, b, c;
void swap(int &x, int &y, int &z){ //将a,b,c排序
if (x > y) swap(x, y);
if (x > z) swap(x, z);
if (y > z) swap(y, z);
}
int main(){
cin >> a >> b >> c;
swap(a, b, c);
if (a + b + c != 180) cout << "Error" << endl;
else if (a == b && b == c) cout << "Equilateral" << endl;
else if ((a == b || b == c) && a + b == c)
cout << "Isosceles right" << endl;
else if (a == b || b == c || a == c) cout << "Isosceles" << endl;
else if (a + b == c) cout << "Right" << endl;
else cout << "Scalene" << endl;
return 0;
}
T2-区间最大公约数
题目描述
给定两个正整数 L , R L,R L,R, 你可以任意选择两个正整数 x , y x,y x,y 且满足 L ≤ x < y ≤ R L \leq x \lt y \leq R L≤x<y≤R,并求出 x , y x,y x,y 的最大公约数。
请问在所有选法中, x , y x,y x,y 最大公约数的最大值为多少?
输入格式
输入共一行,两个正整数表示 L , R L,R L,R
输出格式
输出共一个整数,表示所求答案
数据范围
∘
\circ
∘ 对于
30
%
30\%
30%的数据,
1
≤
L
<
R
≤
100
1\leq L \lt R \leq 100
1≤L<R≤100
∘
\circ
∘ 对于
60
%
60\%
60% 的数据,
1
≤
L
<
R
≤
1
0
3
1\leq L \lt R \leq 10^3
1≤L<R≤103
∘
\circ
∘ 对于
100
%
100\%
100% 的数据,
1
≤
L
<
R
≤
5
×
1
0
5
1\leq L \lt R \leq 5\times10^5
1≤L<R≤5×105
样例输入1
23 29
样例输出2
4
样例说明1
选(24,28)时,gcd取到最大值为 4
样例输入2
32678 65536
样例输出2
32768
样例输入3
32768 32769
样例输出3
1
分析
很显然,枚举区间肯定会超时。那该怎么办呢?我们可以枚举最大公约数的值,从 l l l到 r r r之间只要可以找到公约数,就把它赋到 a n s ans ans上。我们可以用 f f f来记录左端点,用 e e e记录右端点。如果左端点在右端点的左边,那么 l l l到 r r r之间就有公约数 i i i的倍数, a n s ans ans直接赋成 i i i就行了。哦对了,左端点有两种情况:一是 l l l可以被 i i i整除,这时 f f f直接赋成 l / i l / i l/i就行了;二是 l l l不能被 i i i整除,因为整型除法会向下取整,所以需要特殊处理: l ÷ i + 1 l \div i + 1 l÷i+1。
代码
#include <bits/stdc++.h>
using namespace std;
int l, r, ans = 1;
int main(){
cin >> l >> r;
int f = 0, e = 0;
for (int i = 2; i <= r; ++i){
if (l % i == 0) f = l / i;//左端点
else f = l / i + 1;
e = r / i;//右端点
if (f < e) ans = i;
}
cout << ans << endl;
return 0;
}
T3-滑雪训练
题目描述
小爱最近迷上了滑雪,某滑雪场有 n n n 条不同难度的雪道,只有学习并滑了第 i i i 条雪道,才能去参加第 i + 1 i+1 i+1 条雪道的学习与训练。
已知,第一次滑第 i i i 条雪道时,需要先进行 a i a_i ai 分钟的学习,再花 b i b_i bi 分钟滑该雪道一次,才算学习完成。若之后再滑第 i i i 条雪道,则仅需 b i b_i bi 分钟即可滑一次。
小爱共有 T T T 分钟时间,请问如何安排才能使他能滑的圈数最多?
输入格式
输入第一行,两个正整数
n
,
T
n,T
n,T
接下来
n
n
n 行:每行两个正整数
a
i
,
b
i
a_i,b_i
ai,bi 表示第
i
i
i条雪道需要的学习时间和滑雪时间。
输出格式
输出一个正整数,表示小爱最多可以滑的圈数。
数据范围
∘
\circ
∘ 对于
30
%
30\%
30% 的数据,
1
≤
n
≤
10
1\leq n \leq 10
1≤n≤10
∘
\circ
∘ 对于
60
%
60\%
60% 的数据,
1
≤
n
≤
1
0
3
1\leq n \leq 10^3
1≤n≤103
∘
\circ
∘ 对于
100
%
100\%
100% 的数据,
1
≤
n
≤
1
0
5
,
1
≤
a
i
,
b
i
,
T
≤
1
0
18
1\leq n \leq 10^5,1 \leq a_i,b_i,T \leq 10^{18}
1≤n≤105,1≤ai,bi,T≤1018
样例输入
3 100
10 20
5 5
20 10
样例输出
14
样例说明
先花30分钟学习第一滑道,此时共计滑了一圈
在花10分钟学习第二滑道,此时共计滑了两圈
剩余60分钟,滑第二滑道,共计滑了14圈
分析
因为要求滑最多的圈数,所以我们应该学到滑冰时间最少的圈数,然后剩下的时间全部用来滑这一圈 (花最少的时间,滑最多的圈数) 。那么我们应该怎么实现呢?那就得用——前缀和啦!
s
i
s_i
si表示从第1圈滑到第
i
i
i圈一共要多少时间(只是学习花的时间)。至于
s
s
s数组该怎么算,就不用我讲了叭 (该不会有人还不会求前缀和吧)。
接下来回归正题。我们用循环从
1
−
n
1 - n
1−n枚举只学到第
i
i
i圈,接下来之滑第
i
i
i圈一共能滑多少圈,然后用算出来的数与
a
n
s
ans
ans做个比较,谁大就把谁赋到
a
n
s
ans
ans里。那么问题来了:该怎么算一共能滑多少圈呢?嗯······我们知道
s
i
s_i
si记录着滑到第
i
i
i圈共用多少时间,那么就用总时间
t
t
t减去
s
i
s_i
si,再用求得的值除以
b
i
b_i
bi也就是滑这一圈所需的时间,得到剩余时间还可以滑多少圈,然后再加上
i
i
i,就可以求出一共能滑多少圈啦!
代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
long long n, t, x, b[maxn], s[maxn], ans = 0;
int main(){
cin >> n >> t;
for (int i = 1; i <= n; ++i){
cin >> x >> b[i];
s[i] = s[i - 1] + x + b[i];//前缀和
}
for (int i = 1; i <= n; ++i)
if (t >= s[i])
ans = max(ans, i + (t - s[i]) / b[i]);//滑到第i圈一共所需的时间
cout << ans << endl;
return 0;
}
T4-混乱的文本
题目描述
小爱正在使用一种文本编辑器输入文字。文本编辑器的工作机制如下:
若用户键入一个 [,则光标立即跳到文本的开头;
若用户键入一个 ],则光标立即跳到文本的末尾;
若用户键入任意字母,则在光标处插入该字母,且光标停留在新插入字母的后面。
给定一个字符序列,表示小爱敲击键盘录入的符号序列,请输出最后获得的文本。
输入格式
一个字符序列:表示键入的字符序列。
输出格式
一个字符序列:表示最后获得的文本。
数据范围
设 n n n 表示输入字符序列的长度
∘
\circ
∘
30
%
30\%
30% 的数据,
1
≤
n
≤
1000
1\leq n \leq 1000
1≤n≤1000
∘
\circ
∘
60
%
60\%
60% 的数据,
1
≤
n
≤
20
,
000
1\leq n \leq 20,000
1≤n≤20,000
∘
\circ
∘
100
%
100\%
100% 的数据,
1
≤
n
≤
300
,
000
1\leq n \leq 300,000
1≤n≤300,000
样例输入
abc[xyz]efg
样例输出
xyzabcefg
分析
通过读题我们可以知道:如果读到的是[,那么后面跟着的字母就会插到前面。注意:不是读一个字母就插到前面,而是[后的所有字母都一起插到前面。如果读到的是],那就好办了,直接插到记录答案的字符串
a
n
s
ans
ans里就行了。哦,对了,如果第一个字符是字母的话,直接插到
a
n
s
ans
ans里就可以了。
那我们该怎么解决[的情况呢?我们可以定义一个字符串数组
s
t
st
st,
s
t
n
st_n
stn记录第
n
n
n个[后的所有字母。因为每读到一个[就会插到前面,所以把
s
t
st
st数组从
s
t
n
st_n
stn一直输到
s
t
1
st_1
st1就行了。最后输出
a
n
s
ans
ans就OK了。
代码
#include <bits/stdc++.h>
using namespace std;
string s, ans = "", st[300010];
char js = ']';
int n = 0;
int main(){
cin >> s;
for (int i = 0; i < s.size(); ++i){
if (s[i] == '['){
js = '[';
n++;
}
else if (s[i] == ']')
js = ']';
else{
if (js == '[') st[n] += s[i];
else ans += s[i];
}
}
for (int i = n; i >= 1; --i)
cout << st[i];
cout << ans << endl;
return 0;
}
T5-最大子阵和
题目描述
给定 n × n n \times n n×n 个整数组成一个方阵 a i , j a_{i,j} ai,j,请找一个 k × k k \times k k×k 的子方阵,使得子方阵内的数字之和达到最大,输出这个最大值。
输入格式
第一行:两个整数
n
n
n 与
k
k
k
第二行到第
n
+
1
n+1
n+1 行:每行
n
n
n 个整数表示
a
i
,
j
a_{i,j}
ai,j
输出格式
单个整数:表示最大的 k × k k \times k k×k 的子方阵的数字之和。
数据范围
∘
\circ
∘
30
%
30\%
30% 的数据,
1
≤
k
≤
n
≤
30
1\le k \le n \le 30
1≤k≤n≤30
∘
\circ
∘
60
%
60\%
60% 的数据,
1
≤
k
≤
n
≤
300
1 \le k \le n \le 300
1≤k≤n≤300
∘
\circ
∘
100
%
100\%
100% 的数据,
1
≤
k
≤
n
≤
2500
1 \le k \le n \le 2500
1≤k≤n≤2500
∘
\circ
∘
0
≤
a
i
,
j
≤
1
,
000
,
000
0 \le a_{i,j} \le 1,000,000
0≤ai,j≤1,000,000
样例输入
3 2
1 2 3
3 1 2
0 2 4
样例输出
9
样例说明
右下角最大
分析
这题呢我们需要用到前缀和。注意:这里并不能用一般的方法来求前缀和,因为这里读入的是二维数组。我们用二维数组
s
i
,
j
s_{i,j}
si,j记录从左上角到第
i
,
j
{i,j}
i,j个数所有数的和。那么该怎么求
s
i
,
j
s_{i,j}
si,j的值呢?
如图,
s
i
,
j
=
s
i
−
1
,
j
+
s
i
,
j
−
1
−
s
i
−
1
,
j
−
1
+
t
s_{i,j}=s_{i-1,j}+s_{i,j-1}-s_{i-1,j-1}+t
si,j=si−1,j+si,j−1−si−1,j−1+t。其中
t
t
t为当前读入的数,即图中由绿色、蓝色和红色框起来的小正方形。
求了前缀和,然后就是解决问题了。首先枚举子方阵右下角的坐标,然后再分别推出左上角、左下角和右上角的坐标(分别为
s
i
−
k
,
j
−
k
,
s
i
,
j
−
k
,
s
i
−
k
,
j
s_{i-k,j-k},s_{i,j-k},s_{i-k,j}
si−k,j−k,si,j−k,si−k,j)。用
v
v
v记录当
i
,
j
i,j
i,j为右下角时子方阵的总和,即
s
i
,
j
=
s
i
−
k
,
j
−
k
+
s
i
,
j
−
k
+
s
i
−
k
,
j
s_{i,j}=s_{i-k,j-k}+s_{i,j-k}+s_{i-k,j}
si,j=si−k,j−k+si,j−k+si−k,j。然后用
a
n
s
ans
ans记录
a
n
s
ans
ans和
v
v
v之间的最大值,最后输出就完事儿了。
代码
#include <bits/stdc++.h>
using namespace std;
int n, k, t;
long long s[3000][3000], ans = 0;
int main(){
ios::sync_with_stdio(false);
cin >> n >> k;
memset(s, 0, sizeof(s));
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j){
cin >> t;
s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + t;
}
long long v = 0;
for (int i = k; i <= n; ++i)
for (int j = k; j <= n; ++j){
v = s[i][j] - s[i - k][j] - s[i][j - k] + s[i - k][j - k];
ans = max(ans, v);
}
cout << ans << endl;
return 0;
}
对了:用 c i n cin cin语句读入会超时,需要改成 s c a n f scanf scanf读入或写一行取消缓冲区同步的代码。