T1 三角形的分类
题目描述
给定三个角度 a,b 及 c。请判断这三个角在平面上能组成什么样的三角形:
如果不能组成三角形,输出 Error
如果能组成等边三角形,输出 Equilateral
如果能组成等腰直角三角形,输出 Isosceles right
如果能组成等腰三角形,输出 Isosceles
如果能组成直角三角形,输出 Right
如果能组成不等边三角形,输出 Scalene
输入格式
第一行:第一个角的角度 a
第二行:第二个角的角度 b
第三行:第三个角的角度 c
输出格式
根据题目要求输出对应的文字
数据范围
1≤a,b,c≤180
样例数据
输入:
60
60
60
输出:
Equilateral
分析
这题虽然直接可以用if语句套嵌,但这题给你的描述正好是把三角形的所有可能性从小到大给你了,否则还要考虑会不会出现如:把等腰直角三角形输成等腰或直角三角形的情况。
代码
#include <bits/stdc++.h>
using namespace std;
int a, b, c;
int main(){
cin >> a >> b >> c;
if (a < b) swap(a, b);
if (b < c) swap(b, c);
if (a < b) swap(a, b);
//将abc从大到小排序,方便判断
if (a + b + c != 180) printf("Error");
else if (a == 60 && b == 60 && c == 60)
printf("Equilateral");
else if (a == 90 && b == c)
printf("Isosceles right");
else if (a == b || a == c || b == c)
printf("Isosceles");
else if (a == 90)
printf("Right");
else
printf("Scalene");
return 0;
}
T2 区间最大公约数
题目描述
给定两个正整数L,R,你可以任意选择两个正整数x,y且满足L≤x<y≤R,并求出x,y的最大公约数。请问在所有选法中,x,y最大公约数的最大值为多少?
输入格式
输入共一行,两个正整数表示L,R
输出格式
输出共一个整数,表示所求答案
数据范围
对于30%的数据,1≤L<R≤100
对于60%的数据,1≤L<R≤
1
0
3
10^3
103
对于100%的数据,1≤L<R≤
5
×
1
0
5
5×10^5
5×105
样例数据
输入:
23 29
输出:
4
说明:
选(24,28)时,取到最大值为 4
输入:
32768 32769
输出:
1
分析
已知,对于两个数 a × c 和 a × ( c − 1 ) a\times c和a \times (c-1) a×c和a×(c−1),其中a一定是他们两个数的公因数,所以如果 a × c 和 a × ( c − 1 ) a\times c和a \times (c-1) a×c和a×(c−1)在l~r之间,那么a就是其中的公因数,那么我们就可以枚举所有可能解了
代码
#include <bits/stdc++.h>
using namespace std;
int l, r, ans = 1;
int main(){
cin >> l >> r;
for (int i = 2; i <= r; i++){
int x = r / i * i;
if (x - i >= l) 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条雪道需要的学习时间和滑雪时间。
输出格式
输出一个正整数,表示小爱最多可以滑的圈数。
数据范围
对于30%的数据,
1
≤
n
≤
10
1\leq n \leq 10
1≤n≤10
对于60%的数据,
1
≤
n
≤
1
0
3
1\leq n \leq 10^3
1≤n≤103
对于100%的数据,
1
≤
n
≤
1
0
5
1\leq n \leq 10^5
1≤n≤105,
1
≤
a
i
,
b
i
,
T
≤
1
0
18
1 \leq a_i,b_i,T \leq 10^{18}
1≤ai,bi,T≤1018
样例数据
输入:
3 100
10 20
5 5
20 10
输出:
14
说明:
先花30分钟学习第一滑道,此时共计滑了一圈
在花10分钟学习第二滑道,此时共计滑了两圈
剩余60分钟,滑第二滑道,共计滑了14圈
分析
这题可以枚举学习到哪一条赛道。
首先,我们可以把总时间T分为学习时间(
a
i
a_i
ai)和滑雪时间(
b
i
b_i
bi)。
b
i
b_i
bi一定是学完后时间最少的一条赛道,才能使划得圈数最多。其中
a
i
a_i
ai确定之后,
b
i
b_i
bi也可以确定,就是你学习后的最后一条,因为如果目前耗时最少的不是最后一条,那从最少的那一条往后都不该学习,所以一定不是最优解,而如果他不是最优解,那么在比较是就会被舍去。
代码
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 10;
long long n, t, b[MAXN], tim[MAXN];
int main(){
cin >> n >> t;
memset(tim, 0, sizeof(tim));
for (int i = 1; i <= n; i++){
int a;
cin >> a >> b[i];
tim[i] = tim[i - 1] + a + b[i]; //记录学习到第i条所需的时间
if (tim[i] > t){//数据最大时会爆long long,进行判断
n = i - 1;
break;
}
}
long long ans = 0;
for (int i = 1; i <= n; i++){
long long a = t - tim[i];
ans = max(ans, a / b[i] + i);//比较圈数
}
cout << ans << endl;
return 0;
}
T4 混乱的文本
题目描述
小爱正在使用一种文本编辑器输入文字。文本编辑器的工作机制如下:
若用户键入一个 [,则光标立即跳到文本的开头;
若用户键入一个 ],则光标立即跳到文本的末尾;
若用户键入任意字母,则在光标处插入该字母,且光标停留在新插入字母的后面。
给定一个字符序列,表示小爱敲击键盘录入的符号序列,请输出最后获得的文本。
输入格式
一个字符序列:表示键入的字符序列。
输出格式
一个字符序列:表示最后获得的文本。
数据范围
设 nn 表示输入字符序列的长度
30% 的数据,
1
≤
n
≤
1000
1\leq n \leq 1000
1≤n≤1000
60% 的数据,
1
≤
n
≤
20
,
000
1\leq n \leq 20,000
1≤n≤20,000
100% 的数据,
1
≤
n
≤
300
,
000
1\leq n \leq 300,000
1≤n≤300,000
样例数据
输入:
abc[xyz]efg
输出:
xyzabcefg
分析1
我在第一次做时首先想到字符串中自带的insert函数,只要用一个变量记录光标位置,根据 “ [ ”“ ] ” “[” “]” “[”“]”改变位置。
代码1
#include <bits/stdc++.h>
using namespace std;
string s, ans;
int k = 0;
int main(){
cin >> s;
int l = s.size();
int len = 0;
for (int i = 0; i < l; i++){
string ss = "";
ss += s[i];
if (s[i] == '[') k = 0;//改变位置
else if (s[i] == ']') k = len;
else {
len++;
ans.insert(k, ss);
k++;
}
}
cout << ans << endl;
return 0;
}
不知道insert函数的时间复杂度,初测100,复测80,两个点超时。
分析2
可以把给定的字符串由 [ ] 分开,当出现 [ 时,用另一个字符串记录下来,出现 ] 时在第一个数组后面添加,最后倒叙输出。
代码2
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 3e5 + 10;
string s, ans[MAXN];
int num = 1, n = 1;//num是当前是第几个字符串,n是一共多少字符串
int main(){
cin >> s;
int l = s.size();
int len = 0;
for (int i = 0; i < l; i++){
if (isalpha(s[i])){
ans[num] += s[i];
}else{
if (s[i] == '['){
n++;
num = n;
}else{
num = 1;
}
}
}
for (int i = n; i >= 1; i--)
cout << ans[i];
cout << 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 与 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 的子方阵的数字之和。
数据范围
30% 的数据,
1
≤
k
≤
n
≤
30
1\leq k\leq n\leq 30
1≤k≤n≤30
60% 的数据,
1
≤
k
≤
n
≤
300
1\leq k\leq n\leq 300
1≤k≤n≤300
100% 的数据,
1
≤
k
≤
n
≤
2500
1\leq k\leq n\leq 2500
1≤k≤n≤2500
0
≤
a
i
,
j
≤
1
,
000
,
000
0\leq a_{i,j}\leq 1,000,000
0≤ai,j≤1,000,000
样例数据
输入:
3 2
1 2 3
3 1 2
0 2 4
输出:
9
说明:
右下角最大
分析1:枚举
枚举子阵的左上角的位置( a 1 , 1 到 a n − k + 1 , n − k + 1 a_{1,1}到a_{n-k+1,n-k+1} a1,1到an−k+1,n−k+1),循环将子阵和求出并比较。
代码1
#include <bits/stdc++.h>
using namespace std;
int n, k;
int a[3010][3010];
int main(){
cin >> n >> k;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
cin >> a[i][j];
int ans = -1;
for (int i = 1; i <= n - k + 1; i++){
for (int l = 1; l <= n - k + 1; l++){
int an = 0;
for (int j = 0; j < k; j++){
for (int q = 0; q < k; q++)
an += a[i + j][l + q];
}
ans = max(ans, an);
}
}
cout << ans << endl;
return 0;
}
时间复杂度 O ( n 4 ) O(n^4) O(n4),应该30分,但初测复测都是60
分析2:前缀和
对于求字段大小的问题,都可以用前缀和做,只不过这题从常规的一维升到了两维,存储方式稍微变化
对于上图,将
a
[
x
,
y
]
a[x,y]
a[x,y]的值转化为它的面积,那么
a
x
,
y
=
a
x
,
y
−
1
+
a
x
−
1
,
y
−
a
x
−
1
,
y
−
1
+
m
a_{x,y}=a_{x,y-1}+a_{x-1,y}-a_{x-1,y-1}+m
ax,y=ax,y−1+ax−1,y−ax−1,y−1+m
根据存好的数组求出对应的子阵和,进行比较
所以对于点a[x,y],当其作为子阵右下角的点时:
S
=
a
x
,
y
−
a
x
−
k
,
y
−
a
x
,
y
−
k
+
a
x
−
k
,
y
−
k
S=a_{x,y}-a_{x-k,y}-a_{x,y-k}+a_{x-k,y-k}
S=ax,y−ax−k,y−ax,y−k+ax−k,y−k
因为n最大为2500,也就是说最多要读入6250000个数,用cin,scanf读入会超时。即使关闭流同步,很多点是靠运气过得。
代码2
#include <bits/stdc++.h>
using namespace std;
long long n, k, ans;
long long x[2560][2560];
int main(){
std::ios::sync_with_stdio(false);
memset(x, 0, sizeof(x));
cin >> n >> k;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++){
int num;
cin >> num;
x[i][j] = x[i - 1][j] + x[i][j - 1] - x[i - 1][j - 1] + num;
}
for (int i = k; i <= n; i++){
for (int j = k; j <= n; j++){
long long v = x[i][j] - x[i - k][j] - x[i][j - k] + x[i - k][j - k];
ans = max(ans, v);
}
}
cout << ans << endl;
return 0;
}