上海计算机学会12月月赛-丙组解题报告

上海计算机协会12月月赛-丙组解题报告

T1-多边形的内角和

题目描述
一个 n 条边的多边形,其内角和公式为 180×(n−2)。给定 n,请计算并输出 n 边形的内角和。
输入格式
单个整数:表示 n。
输出格式
单个整数:表示 n 边形的内角和。
数据范围
3≤n≤100
样例数据
输入:
3
输出:
180
输入:
5
输出:
540

题目出处
很简单,公式都给出来了,数据也不大,照着写。

#include <bits/stdc++.h>
using namespace std;

int n; 

int main(){
	cin>>n;
	n=180*(n-2);
	cout<<n<<endl;
	return 0;
}

T2-星号三角阵(二)

题目描述
给定一个整数 nn,输出一个 n 行 n 列的星号三角阵,直角位于图形的左上角。例如当 n=4,n=4 时,输出

****
***
**
*

输入格式
单个整数表示 n。
输出格式
共 n 行:表示一个星号三角阵。
数据范围
1≤n≤100
样例数据
输入:
3
输出:

***
**
*

题目出处
这题也很简单。非常生动形象(几乎不需要程序设计思维)

#include <bits/stdc++.h>
using namespace std;

int n; 

int main(){
	cin>>n;
	for(int i=n;i>=1;--i){
		for(int j=1;j<=i;++j)
			cout<<"*";
		cout<<endl;
	}
	return 0;
}

T3-折纸

题目描述
小爱手中有一张矩形纸张,他想把这张纸分成若干正方形纸片,具体分法如下:
第1步:小爱会先确定纸张的长宽,假设短边长度为n,长边长度为m。
第2步:小爱会将短边沿直角平分线对折后剪去,从而得到一个n×n的方形纸片。
第3步:若还有剩余,小爱会将剩余的长宽为n∗(m−n)的纸张作为现有纸张,代入第一步后重复之前过程,直至没有之后纸张剩余为止。
请问按如上操作,小爱最终会得到几张方形纸片?
例如:一开始,小爱有一张 10×6 的纸张,按他的分割方法,最终他可以获得 4 张方形纸片,具体过程如下图所示:
在这里插入图片描述
输入格式
输入共两个正整数,表示初始矩形纸张的长宽 n,m
输出格式
输出题目所求能获得的矩形个数
数据范围
对于 30% 的数据,1≤n,m≤100
对于 60% 的数据,1≤n,m≤10^7
对于 100% 的数据,1≤n,m≤10^13
样例数据
输入:
10 6
输出:
4

题目出处
这题,如果按照题目说的做(即题目怎么说,我怎么做)。可以拿60分。

#include <bits/stdc++.h>
using namespace std;

int n,m; 

int main(){
	cin>>n>>m;
	if(n>m)swap(n,m);
	int ans=0;
	while(m!=0){
		++ans;
		if(n>m)swap(n,m);
		m-=n; 
	}
	cout<<ans<<endl;
	return 0;
}

仔细一看,数据范围……
再想一想杨老师说的“我最讨厌那些初学者乱用循环”,再看一看++ans;m-=n;……有必要吗?
于是改为了:ans+=m/n;m%=n;

#include <bits/stdc++.h>
using namespace std;

long long n,m; 

int main(){
	cin>>n>>m;
	if(n>m)swap(n,m);
	long long ans=0;
	while(m!=0){
		if(n>m)swap(n,m);//因为已经改成m%=n了,m必定小于n,所以if可以省略
		ans+=m/n;
		m%=n; 
	}
	cout<<ans<<endl;
	return 0;
}

这题估算时间复杂度算了半天,也没算出来。仔细一看,这不就是辗转相除法算最大公约数吗?于是时间复杂度是O(log n),因为m%=n;其实就是m=m-n*k。
当然也可以用递归解法。

#include <bits/stdc++.h>
using namespace std;

long long n,m,ans; 

void gcd(long long m,long long n){
    ans+=m/n;
    gcd(n,m%n);
}

int main(){	
    cin>>n>>m;	
    if(n>m)swap(n,m);
    gcd(m,n);
   	cout<<ans<<endl;	
   	return 0;
}

T4-中位数(二)

题目描述
中位数,就指将所有数字排序后,位置在最中间的数。
给定 n 个数字的序列 a_1,a_2,…,a_n ,以及一个期望中位数 x。小爱想知道,最少再添加多少个数字,才能使序列中包含奇数个数字,且 x 为该序列的中位数?
输入格式
输入共三行:
第一行,一个正整数 n ,表示元素个数
第二行,n 个整数,分别表示 a_1,a_2,…,a_n
第三行,一个整数 x ,表示期望中位数
输出格式
输入一个整数,表示答案
数据范围
对于 30% 的数据, 1≤n≤100
对于 60% 的数据, 1≤n≤10^4
对于 100% 的数据,1≤n≤10^5, −10^9 ≤x,a_i≤10^9
样例数据
输入:
4
6 4 7 1
3
输出:
3
说明:
加1个3 和 2个1,就可以让3成为中位数
输入:
5
1 2 3 4 5
3
输出:
0
说明:
不用添加任何数字,3已经是中位数

题目出处
……这题,应该比较难。
我的大概思路是:先查找x,没有的话++ans;++n;a[n]=x;插一个x进去,先排一下序,再查一下x的现在位置,再算一下他与中位数位置差再×2(因为每加一个数可以使x的位置改变0.5)就是结果。
但是要解决一个精度问题,如果用double或float存,那么有可能会将7存成6.999999999,那时强转成int再输出就会出错而且也不便于处理(n是奇数中位是half+1),当然可以保留小数位数解决(但我不想写了……)。
好吧,我收回上面的话,我错了……应该写小数的……而不是标记是否为偶数导致公式复杂化……就是这题初测100实测90……

90分代码:

#include <bits/stdc++.h>
using namespace std;

long long n,a[100010],ans,x,x1; 

int main(){
	cin>>n;
	for(int i=1;i<=n;++i){
		cin>>a[i];
	}
	cin>>x;
	bool bl=0;
	for(int i=1;i<=n;++i){
		if(a[i]==x){
			bl=1;
			break;
		}
	}
	if(bl)sort(a+1,a+1+n);
	else{
		++ans;
		++n;
		a[n]=x;
		sort(a+1,a+1+n);
	}
	int half,half1;
	if(n%2==1)half1=1;
	else half1=0;
	half=n/2;
	for(int i=1;i<=n;++i){
		if(a[i]==x&&i<=half)x1=i;
		else if(a[i]==x){
			if(i-half<=abs(half-x1)){
				x1=i;
				break;
			}
		}
	}
	if(half1){
		ans+=abs(half+1-x1)*2;
	}
	else{
		ans+=abs(half+0.5-x1)*2;
	}
	cout<<ans<<endl;
	return 0;
}

AC code:

#include <bits/stdc++.h>
using namespace std;

int n,a[100010],x;
double ans;

int main(){
   scanf("%d",&n);
   for(int i=1;i<=n;++i)
       scanf("%d",&a[i]);
   scanf("%d",&x);
   int find=0;
   bool task=1;
   for(int i=1;i<=n;++i)
       if(a[i]==x)task=0;//是否有x
   if(task){
       a[++n]=x;
       ++ans;//没有的话补上一个
       sort(a+1,a+1+n);//对其进行排序以便查出真实位置
   }
   else sort(a+1,a+1+n);
   double half=(n+1)/2.0;//算“中位”
   for(int i=1;i<=n;++i)
       if(a[i]==x&&(fabs(half-i)/*注意这里取绝对值运算因为返回值是实数所以应该用fabs而非abs*/<fabs(half-find)||find==0)){
           find=i;
       }//查找x
   ans+=fabs(half-find)*2;
   cout<<fixed<<setprecision(0)<<ans<<"\n";
   return 0;
}

T5-等差数列

题目描述
等差数列 指从第二项起,每一项与它的前一项的差等于同一个常数的一种数列,且这个常数叫做等差数列的公差。
例如:数列 1 5 9 13 就是一个公差为 2 的等差数列。
现给定一个长度为 n 的序列 a_1,a_2,…,a_n,请问该序列中,有多少个长度不小于 3 的子段满足等差数列?
输入格式
输入共两行:
第一行,一个正整数 n,表示给定序列长度
第二行,n 个整数,分别表示序列的每一项 a_1,a_2,…,a_n
输出格式
输出一个整数,表示满足条件的子段个数。
数据范围
对于30% 的数据, 1≤n≤100
对于60% 的数据, 1≤n≤10
4
对于 100% 的数据,1≤n≤10^5 ,−10^9 ≤a_i≤10^9
样例数据
输入:
10
-1 1 3 3 3 2 3 2 1 0
输出:
5
说明:
区间[1,3],[3,5],[7,10],[7,9],[8,10]均满足等差数列要求

题目出处
原本想写个O(n2)算法,但灵机一动,写了个O(n)的。
具体看注释吧。

#include <bits/stdc++.h>
using namespace std;

long long n,a[100010],ans; 

int main(){
	cin>>n;
	for(int i=1;i<=n;++i)cin>>a[i];
	a[0]=2e9;//必须保证a[2]-a[1]!=a[1]-a[0]
	long long last=a[2]-a[1],wide=0;
	for(int j=1;j<=n;++j){
		if(last==a[j]-a[j-1])++wide;//wide是当前块的长度
		else{
			--j;//结束时会++j,为了以a[j]作为一段新块的开头,要保持j不变,--j与++j抵消。
			if(wide>=3)ans+=(wide-1)*(wide-2)/2;//乘法原理算长度大于等于3的块个数
			wide=1;
			last=a[j+1]-a[j];//重新初始化
		}
	}
	if(wide>=3)ans+=(wide-1)*(wide-2)/2;//最后还要再加一遍以防最后一个块没有算上去
	cout<<ans<<endl;
	return 0;
}

终于结束了,完工了(都是这个中位数他们说不难,结果在我看来是最难的)!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GaoGuohao2022

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值