第六周周赛题解
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;
}