上海市计算机学会竞赛平台 5月月赛 丙组

T1 三角形的分类

题目描述

给定三个角度 abc。请判断这三个角在平面上能组成什么样的三角形:

如果不能组成三角形,输出 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×ca×(c1),其中a一定是他们两个数的公因数,所以如果 a × c 和 a × ( c − 1 ) a\times c和a \times (c-1) a×ca×(c1)在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 1n10
对于60%的数据, 1 ≤ n ≤ 1 0 3 1\leq n \leq 10^3 1n103
对于100%的数据, 1 ≤ n ≤ 1 0 5 1\leq n \leq 10^5 1n105 1 ≤ a i , b i , T ≤ 1 0 18 1 \leq a_i,b_i,T \leq 10^{18} 1ai,bi,T1018

样例数据

输入:
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 1n1000
60% 的数据, 1 ≤ n ≤ 20 , 000 1\leq n \leq 20,000 1n20,000
100% 的数据, 1 ≤ n ≤ 300 , 000 1\leq n \leq 300,000 1n300,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 1kn30
60% 的数据, 1 ≤ k ≤ n ≤ 300 1\leq k\leq n\leq 300 1kn300
100% 的数据, 1 ≤ k ≤ n ≤ 2500 1\leq k\leq n\leq 2500 1kn2500
0 ≤ a i , j ≤ 1 , 000 , 000 0\leq a_{i,j}\leq 1,000,000 0ai,j1,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,1ank+1,nk+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,y1+ax1,yax1,y1+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,yaxk,yax,yk+axk,yk

因为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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值