CSDN第39期竞赛题解

文章包含四个编程题目,分别是关于同心圆的染色问题,考虑近视度数影响的视线遮挡问题,单次买卖股票的最大收益,以及购买铅笔的最经济策略。每个问题都涉及算法设计和数学思维,如排序、单调队列、二分查找和最优化计算。
摘要由CSDN通过智能技术生成

1、题目名称:圆小艺

最近小艺酱渐渐变成了一个圆滑的形状-球!! 小艺酱开始变得喜欢上球! 小艺酱得到n个同心圆。 小艺酱对着n个同心圆 进行染色。 相邻的圆范围内不能有相同的颜色。相隔一层的圆颜色相同。 小艺酱想知道两种颜色中最外层圆的那种颜色总 共染了多少?

分析 :

这题似乎在以前的比赛中有出现过,这里就直接照搬以前的题解了。

圆环面积公式
S = π ( R 2 − r 2 ) , R > r S=\pi(R^2-r^2),R>r S=π(R2r2),R>r
先按半径大小排序
奇数层染一种颜色,偶数层染一种
最后根据n的奇偶性输出
注意精度问题
当然要精准的可以 π = arccos ⁡ ( − 1 ) \pi=\arccos(-1) π=arccos(1)

扩展

x & 1 x \& 1 x&1表示取二进制最后一位,若 x & 1 = 1 x\&1=1 x&1=1表示其为奇数,
等同于 x m o d    2 = 1 x\mod 2 =1 xmod2=1

#include<bits/stdc++.h>
using namespace std;
const double pie = 3.1415926535897932846;
double a[11000],s1,s2;
int main(){
	int n; cin >> n;
	for(int i=1;i<=n;i++) cin >> a[i];
	sort(a+1,a+1+n);
	for(int i=1;i<=n;i++)
		if(i & 1) s1 += pie*(a[i]*a[i]-a[i-1]*a[i-1]);
		else s2 += pie*(a[i]*a[i]-a[i-1]*a[i-1]);
	if(n&1) printf("%.3lf",s1);
	else printf("%.3lf",s2);
	return 0;
}

2、题目名称:近视的小张

小张和他的 M 个朋友来到了一个十分神奇的地方,在这里有 N 个 柱子, 对于每个 1 <= i <= N, 第 i 个柱子都有两个
属性 : H[i], P[i]。
H[i] 表示柱子 i 的高度, 而 P[i] 则表示柱子 i 当前所处的位置,题目保证同一个位置不会有多个柱子。
在一个柱子 i 在另一个不比他低的柱子 j 的后面时 (P[i] > P[j] && H[i] <= H[j]), 这个柱子会被遮挡住, 也就不再能被
清晰的看到。
小张和他的朋友们在位置 0 休息时, 发现似乎朋友们能清晰看到的柱子数量并不相同,在他反复思考后, 他认为这可能
是近视度数导致的,于是他询问了每一个朋友的近视度数 A[i]。
为了方便计算, 我们认为对于朋友 j 来说,对每一个柱子 i, 如果有 P[i] > A[j], 那么第 i 个柱子无法被清晰看见。
请你计算出每个小张的朋友能清晰看到的最远一个柱子的位置, 如果那个朋友一个柱子都没有清晰看到, 请输出 -1。

分析

这题我只有80分,但找不出哪有问题,就给大家说一下我的思路,如果有哪位大佬能指出我代码的漏洞,可在评论区留言,谢谢。

我先将每根柱子按距离从小到大排序,然后构造一个单调队列使这些柱子的高度单调递增,即预处理出满足条件的柱子。
然后就是找到每个人能看到的最远的柱子,其实就是在一些柱子的距离{ P n P_n Pn}中,给定一个数 A A A,找到满足 P i ≤ A P_i \le A PiA的最大 P i P_i Pi
很快就能想到两种思路,因为{ P n P_n Pn}经过刚才的处理是单调递增的,所以可以用二分查找;另一种思路则是将{ A n A_n An}排序,然后用双指针。两种方法我都写在代码中,都是80分。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e5+10;
ll n,m;
ll ans[N];
ll q[N],tail;
struct node{
	ll h,p;
}l[N];
bool cmp1(node x,node y){
	return x.p < y.p;
}
struct stu{
	ll a,id;
}s[N];
bool cmp2(stu x,stu y){
	return x.a < y.a;
}
int main(){
	cin >> m >> n;
	for(int i=1;i<=n;i++) cin >> l[i].h;
	for(int i=1;i<=n;i++) cin >> l[i].p;
	for(int i=1;i<=m;i++){
		cin >> s[i].a;
		s[i].id = i;
	}
	sort(l+1,l+1+n,cmp1);
	ll lst = 0;
	for(int i=1;i<=n;i++)
		if(l[i].h >= l[lst].h) q[++tail] = l[i].p,lst = i;
	
	sort(s+1,s+1+m,cmp2);
	for(int i=1,j=1;i<=m;i++){
		if(q[j] <= s[i].a) ans[s[i].id] = q[j];
		else ans[s[i].id] = -1;
		while(q[j+1] <= s[i].a && j<tail)
			ans[s[i].id] = q[++j];
	}//双指针
	
	/*for(int i=1;i<=m;i++){
		int l=1,r=tail,mid;
		while(l < r){
			mid = (l+r+1)/2;
			if(q[mid] <= a[i]) l = mid;
			else r = mid-1;
		}
		if(q[l] <= a[i]) ans[i] = q[l];
		else ans[i] = q[l-1];
		if(ans[i] == 0) ans[i] = -1;
	}*///二分查找
	
	for(int i=1;i<=m;i++)
	cout << ans[i] << "\n";
	return 0;
}

3、题目名称:小股炒股

已知n天后的股票行情,现在已有的本金是m, 规定只能入手一次股票和抛售一次股票。 最大收益(含本金)是?

分析

没什么好说的,因为只能入手和抛售一次,所以从后往前枚举求出最大的一天的股票,然后模拟求最值,具体可以看代码。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int p[1010];
int n,m;
int main(){
	cin >> n >> m;
	for(int i=1;i<=n;i++) cin >> p[i];
	int maxn = 0,ans = 0;
	for(int i=n;i>=1;i--){
		maxn = max(maxn,p[i]);
		ans = max(ans,m+(maxn-p[i])*(m/p[i]));
	}
	cout << ans;
	return 0;
}

4、题目名称:买铅笔

P老师需要去商店买n支铅笔作为小朋友们参加编程比赛的礼物。她发现商店一共有 3 种包装的铅笔,不同包装内的铅笔数
量有可能不同,价格也有可能不同。为了公平起 见,P老师决定只买同一种包装的铅笔。 商店不允许将铅笔的包装拆开,
因此P老师可能需要购买超过 n 支铅笔才够给小朋 友们发礼物。 现在P老师想知道,在商店每种包装的数量都足够的情况
下,要买够至少 n 支铅笔最少需要花费多少钱。

分析

小学生数学题,三种的金额都算一下然后取最小值就行了。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n,ans = 9999999;
int a[4],b[4];
int main(){
	cin >> n;
	for(int i=1;i<=3;i++){
		cin >> a[i] >> b[i];
		ans = min(ans,int(ceil(n*1.0/a[i])*b[i]));
	}
	cout << ans;
	return 0;
}
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值