2023年寒假算法训练营周赛Round 3

P5724 【深基4.习5】求极差 / 最大跨度值

题目链接

题意

给出 n 和 n 个整数 a i,求这n 个整数中的极差是什么。极差的意思是一组数中的最大值减去最小值的差。

思路

  1. 运用最大值减去最小值

坑点

算法一:

实现步骤
  1. 将最大值减去最小值
代码
#include<bits/stdc++.h>
using namespace std;
int a[100001];//将在a数组里
int main()
{
        int n;
        cin>>n;
    for(int i=1;i<=n;i++)
    {
            cin>>a[i];
        }
        sort(a+1,a+n+1);
        cout<<a[n]-a[1];//a[n]为最大值,-a[1] 为最小值 
    return 0;
}


总结

一道很简单的基础题

题目名字

题目链接

题意

设有一个
N×M方格的棋盘(1≤N≤100,1≤M≤100)求出该棋盘中包含有多少个正方形、多少个长方形(不包括正方形)。

思路

  1. 找规律

坑点

  1. 不注意正方形以及长方形的区分

算法一

实现步骤

1.小写为正方形个数,大写为长方形加上正方形个数

代码
#include<iostream>
#include<cmath>    //头文件 
int n,m,sum,N,M,SUM;  //定义,小写的是求正方形个数的 ,大写的是求正方形+长方形个数的 
int main()
{
    cin>>n>>m;   //读入棋盘的长和宽
    //输入
    for(int i=1; i<=min(n,m); i++)  //枚举边长,记住min(n,m),因为正方形只能由小的那条边作为边长,记住,这个min函数是在cmath库里调用的
    	sum+=(n-i+1)*(m-i+1);  //套公式(n-边长+1)*(m-边长+1)
    //求正方形,知识点:1.正方形只能由小的那条边作为边长  2.对于不同边长的正方形就有(棋盘边长-枚举变长+1)条边
    for(int i=1; i<=n; i++) 
    	N+=i;               //求一条长的和,累加1~n
    for(int i=1; i<=m; i++)
    	M+=i;               //求一条宽的和,累加1~m
    SUM=N*M-sum;        //根据(1~n的和)*(1~m的和)-正方形的个数算出长方形个数
    //求长方形,知识点:公式的推导
    cout<<sum<<" "<<SUM;  //输出正方形个数和长方形个数
    //输出
    return 0;
}
 
 

总结

数学奥数问题

P3397 地毯

题目链接

题意

在n*n的方格内铺m个地毯,在得知地毯所涉及的坐标后,求每一个坐标上被覆盖到的地毯数

思路

1.记住最大值减去最小值

坑点

  1. 图容易看错

算法一

实现步骤
  1. 由样例来进行推导
代码
#include<cstdio>
#include<iostream>
using namespace std;
int cf[2000][2000];
int main()
{
    int n,m;
    int x1,y1,x2,y2;
    scanf("%d%d",&n,&m);
    while(m--)//循环的另一种方式(m==0时,会自动跳出,所以循环m遍).
    {
        scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
        for(int i=x1;i<=x2;i++)//每一行进行差分,时间复杂度O(N)
        {
            cf[i][y1]++;
            cf[i][y2+1]--;//差分
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            cf[i][j]+=cf[i][j-1];//复原,利用A[I]-A[I-1]=B[I],可以推得B[I]+A[I-1]=A[I](因为B[I-1]已被复原为A[I-1],所以得到此递推公式)
            printf("%d ",cf[i][j]);//复原后输出
        }
        printf("\n");//换行
    }
    return 0;
}
 
 

算法二

实现步骤
  1. 定义二维数组
  2. 利用for循环计算每个坐标点上存在的地毯数
代码
using namespace std;
int a[1010][1010];
int main()
{
        int n,m;
        cin>>n>>m;
        int x1,y1,x2,y2; //定义左上方与右下方的坐标点
        for (int i=1;i<=m;i++)
        {
                cin>>x1>>y1>>x2>>y2;
                for (int j=x1;j<=x2;j++)
                {
                        for(int k=y1;k<=y2;k++)
                        {
                                a[j][k]++;
                        }
                }
        }
        for (int i=1;i<=n;i++)
        {
                for (int j=1;j<=n;j++)
                {
                        cout<<a[i][j]<<" ";
                }
                cout<<endl;
        }
        return 0;
}
 
 

P2021 faebdc玩扑克

题目链接

题意

zky 有 n 个扑克牌,编号从 11 到 n,zky 把它排成一个序列,每次把最上方的扑克牌放在牌堆底,然后把下一张扑克牌拿出来输出,最终输出的序列恰好是从 11 到 n,faebdc 问你原序列是什么,因为 faebdc 神犇早已在 O(1)的时间得出结果,如果你在1 s内答不出来,faebdc会吃了你。

思路

1.运用了约瑟夫问题

算法一

stl,链表

实现步骤
  1. 首先,在做此题之前,我们需要了解到的一点是:不管一张牌上面写的数字是几,只要牌的总量不变,牌的位置不变,最终这张牌到达的位置总是不变的
  2. 我们需要求的一个关键数组是每个位置的同学(牌)换座位(洗牌)之后被换到了哪个位置。
代码
 #include <bits/stdc++.h>
using namespace std;
int a[1000001];
int n;
int b(int x)
{
        int t;
        t=x+1;
        if (t>n)
                {
                        t-=n;
                }
}
int main(){
        int i,j,s=0;
        scanf("%d",&n);
        for (i=1;i<=n;i++)        
        {
                for (j=1;j<=2;j++) 
                                {
                        s++;
                        if (s>n) 
                                                {
                                                        s-=n;
                                                }
                        while (a[s]!=0) 
                                                {
                                s++;        
                           if (s>n) 
                                                        {
                                                                s-=n;
                                                        }
                        }
                }
                a[s]=i;
        }
        for (i=1;i<=n;i++) 
                printf("%d ",a[i]);//每个数之间要空一格 
        return 0;
}