第六周周赛题解

第六周周赛题解

A.小鱼的数字游戏

这道题大概是写过的,没什么好说的,暴力循环一直到输入为0的时候直接逆序输出就好了。

#include <iostream>
using namespace std;

int main() {
	int a[200],i=0;
	for(int i=0;i<200;i++){
		scanf("%d",&a[i]);
//		printf("%d\n",a[i]);
		if (a[i]==0){
			for(int j=i-1;j>=0;j--){
				printf("%d ",a[j]);
			}
			return 0;	
		}
	}			
	return 0;
}

B.缘分

这道题本质上就是要求在0~n范围内,找到两数使得两数的最小公倍数在范围内最大,那我们很容易想到,两数最小公倍数在互质时最大,又两个连续的自然数一定是互质数,那么答案就是n*(n-1),然后特别注意当n=1的时候,直接输出1。

#include <iostream>
using namespace std;
int main()
{
	int T;
	cin >> T;
	while (T--)
	{
		int long long n;
		cin >> n;
		if (n == 1)
			cout << 1 << endl;
		else
			cout << n * (n - 1) << endl;
	}
	return 0;
}

C.烦恼的高考志愿

题目要求根据给定的学校的预计分数线和学生的估分情况,为每位学生推荐一所学校,使得每位学生的估分与推荐学校的预计分数线之差最小,然后计算所有学生的不满意度之和的最小值。
具体地,题目给定了学校数m、学生数 n,以及每所学校的预计录取分数和每位学生的估分成绩。对于每位学生,需要找到一个学校,使得该学生的估分与学校的预计分数线的差值最小。然后将所有学生的不
满意度之和输出。

不用二分会超时:

#include <iostream>
#include <algorithm> 
using namespace std;
//超时真的很烦 
int main() {
	int a,b,count=0,min=1000;
	scanf("%d %d",&a,&b);	
	int score[a+5],people[b+5];
	for(int i=0;i<a;i++){ 
		scanf("%d",&score[i]);
	}
	for(int i=0;i<b;i++){
		scanf("%d",&people[i]);
		for(int j=0;j<a;j++){
			int temp=abs(score[j]-people[i]);
			if(temp<min){
				min=temp;
			}
		}
		count+=min;
		min=1000;
	}	
	printf("%d",count);
	return 0;
}

要寻找分数与分数线的最小值,直接套用第二个模板,因为差值有正有负所以要用abs()转换为绝对值进行比较。

具体代码
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int a[1000005];
int b[1000005];
int m,n;
long long int sum;
int main(void)
{
        cin>>m>>n;
        for(int i=0;i<m;i++) cin>>a[i];
        for(int i=0;i<n;i++) cin>>b[i];
        sort(a,a+m);
        for(int i=0;i<n;i++)
        {
                int l=0,r=m-1;
                while(l<r)
                {
                        int mid=l+r>>1;
                        if(a[mid]>=b[i]) r=mid;
                        else l=mid+1;
                }
                if(a[l]==b[i]) continue;
                if(b[i]<=a[0]) {
                        sum+=abs(b[i]-a[0]);
                        continue;
                }
                if(b[i]>=a[m-1]){
                        sum+=abs(b[i]-a[m-1]);
                        continue;
                }
                sum+=min(abs(b[i]-a[l]),abs(b[i]-a[l-1]));
        }
        cout<<sum<<endl;
        return 0;
}

D.国王的魔镜

思路:

观察示例,不难发现ABBAABBA具有回文的特征,为了获得初始的项链可以通过递归的方式不断分解项链,判断是否可以找到最小可能长度。

实现过程:

1.定义一个字符数组 a 用于存储原始项链的排列顺序。
2.定义变量 ans 用于记录分解的次数。
3.实现递归函数 fn,该函数接收一个整数参数 r,表示当前项链的长度。
4.在递归函数中,首先计算项链的中点 mid,然后判断是否可以继续分解。
5.如果当前项链长度为奇数(r%2==1),则直接输出当前项链长度并返回,因为奇数长度无法再分解。
6.否则,使用循环比较项链的前半部分和后半部分是否对称。如果不对称,则输出当前项链长度并返回。
7.如果对称,增加计数 ans,并递归调用 fn,将项链长度缩小为一半。
8.在 main 函数中,使用 gets(a) 读取输入的最终项链,并获取其长度。
9.调用 fn 函数,开始递归过程,找到可能的最小原始项链长度。
10.输出最小可能长度。

具体代码
#include<bits/stdc++.h>
using namespace std;
char a[1000010];//利用a来进行存储原始的排列顺序。
int ans=0;//ans用来记录分解的次数。
void fn(int r)//递归操作
{
    int mid=r/2;//进行分解,对半
    if(r%2==1){//如果分解后发现是奇数则不能再分解直接输出并返回
        cout<<r;
        return;
    }
    else{
        for(int i=0,j=r-1;i<mid;i++,j--){
                //这里i从第一个数开始,j从最后一个开始往内前进
            if(a[i]!=a[j]){
                cout<<r;
                return;
            //发现如果有不同则输出并返回
            }
        } 
    }
    ans++;//计数
    fn(mid);//递归操作,再判断1~mid是否可以再分解
}
int main()
{
    gets(a);
        char t;
    int len=strlen(a);//strlen(字符数组名)是输出字符串的长度
    fn(len); //递归
}

E.激光炸弹

思路:

首先计算整张地图的信息,然后判断遍历整张图找出炸弹能炸到的最大价值。

实现过程:

1.定义一个二维数组a[5010][5010],用于存储地图上每个目标点的价值。数组初始化为0。
2.通过循环读入n个目标点的坐标和价值,并将其存储在数组a中的对应位置。
3.使用动态规划的思想,计算出一个辅助数组a,其中a[i][j]表示以坐标(i, j)为右下角的正方形内目标点的总价值。具体的计算方法如下:
对于每个位置(i, j),首先将其值加上左边的值a[i-1][j],再加上上边的值a[i][j-1],最后减去左上角的值a[i-1][j-1],以消除重复计算。
4.最后,通过两层嵌套循环,遍历地图上的每个点(i, j),计算以该点为右下角的边长为m的正方形内目标点的总价值,并更新ans为最大值。
5.输出ans,即一颗炸弹最多能炸掉地图上总价值为多少的目标。

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

int main(){
    int n,m;
    cin>>n>>m;
    int a[5010][5010]={0};
    for(int i=0;i<n;i++){
        int x,y,v;
        cin>>x>>y>>v;
        a[x][y]=v;
    }
    int ans=0;
    for(int i=0;i<5010;i++){
        for(int j=0;j<5010;j++){
            if(i!=0){
                a[i][j]+=a[i-1][j];
            }
            if(j!=0){
                a[i][j]+=a[i][j-1];
            }
            if(i!=0&&j!=0){
                a[i][j]-=a[i-1][j-1];
            }
        }
    }
    for(int i=0;i<5010;i++){
        for(int j=0;j<5010;j++){
            int sum=a[i][j];
            if(i-m>=0){
                sum-=a[i-m][j];
            }
            if(j-m>=0){
                sum-=a[i][j-m];
            }
            if(i-m>=0&&j-m>=0){
                sum+=a[i-m][j-m];
            }
            ans=max(ans,sum);//取最大值
        }
    }
    cout<<ans<<endl;
}

F.跳石头

思路:

要求两块石头之间最大的跳跃距离,直接套用模板1.

实现过程:

在一条长度为L的河内,有N块石头,每块石头的位置由数组a给出。目标是移走M块石头,并使得相邻石头之间的最短距离最大。可以使用二分查找的方法来寻找最大可能的最短距离。
1.输入:
cin 输入三个整数,分别为道路的长度 L,石头的数量 N,以及要移走的石头数量 M。使用循环读入数组 a,表示每块石头的位置。将数组末尾增加一个元素 a[N+1] = L,表示道路的终点。
2.check函数:
接收一个参数 step,表示两块石头之间的最短跳跃距离。使用循环遍历石头数组,检查相邻石头之间的距离是否小于 step。如果小于 step,增加计数 count。如果移走石头的数量 count 不超过给定的数量 M,则返回1,否则返回0。
3.二分查找:
使用二分查找在可能的最短距离范围内寻找答案。初始化左边界 left 为0,右边界 right 为道路的长度 L。在循环中计算中点 mid,调用 check 函数检查是否可以移走不超过 M 块石头。如果可以,更新答案 ans 为当前的最短距离 mid,并调整左边界。否则,调整右边界。最终输出最大可能的最短距离 ans。
4.输出:
使用cout 输出最终的答案 ans。

#include<iostream>
using namespace std;
const int n=1e6+10;
int L,M,N;
int a[n];
int check(int step)//step表两块石头之间的最短跳跃距离 
{
    int location = 0;//现在所在的位置
    int count = 0;//移走石头的数量
    for(int i = 1 ; i <= N+1 ; i++)
    {
        if(a[i] - a[location] < step)
        {
            count++;
        }
        else location = i;
    }
    if(count <= M) return 1;
    //确保在给定的距离下移走的石头不超过M 
    //小于M,说明还可以移走更多石头 
    else 
        return 0;
}
int main()
{
    cin >> L >> N >> M;
    for(int i=1;i<=N;i++) cin>>a[i];
    a[N+1] = L;//终点 
    int ans ,left = 0,right = L;
    while(left <= right)
    {
        int mid = left + right >> 1;
        if(check(mid)){
            ans = mid;
            left = mid + 1;
        }
        else right = mid - 1;
    }
    cout<<ans;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值