众所周知,国内有不少刷题宝地 力扣 牛客 洛谷 PTA 头歌 等等。
但是要说到世界有名的,那必须是我们最受欢迎的算法网站 Codeforces,该网站的评判机制,题目质量都是很棒的,受到各大算友的喜爱,但是对于我们水平稍低的,暂时可能就是去做做签到题练练手,也是在一步一步成长的过程中,看到自己的积分(codeforces有一个积分机制)慢慢上去,会有自豪感,所以我们来解析一波近些日的签到题。
对于我们是开的新坑,所以我们说明一下以后题目解析的顺序:
1:翻译解释题目(因为codeforces上都是英文,写题目的时候可以网页翻译,但是机器翻译不一定准确,语序也会影响,所以要加入点个人的理解)
2:思路讲解
3:遇到的问题以及解决方法
4:代码展现
Dec/18/2022
题目解释:题目即要求输入一个2x2的各个数字不同的数字矩阵,然后这个数字矩阵可以顺时针旋转90°。然后题目给出了一个定义:如果本体或者旋转之后的矩阵中存在满足以下两个条件的:
在每一行中,第一个元素小于第二个元素;
在每一列中,第一个元素小于第二个元素。
我们则称之为漂亮的矩阵。
然后我们的输入要求,先输入一个 t 表示案例总数(也就是我们这个题目里面最开始的输入 6 在codefores里面 几乎所有的题目第一个要求输入的都是案例数)
接下来输入t组2x2的数字 用于组成矩阵。
输出即 若此组矩阵是漂亮的矩阵 ,则输出YES 反之则为NO;
题目分析结束,那么开始我们的思路分析。
思路一:简单粗暴法。因为我们的矩阵是顺时针旋转90°,在不断的旋转中,其实算上自身,一共也才四个不同的矩阵,而且我们在已知本体矩阵的前提下,是可以把这四个都写出来的,那么我们就可以直接创建四个二维数组,然后对这个四个二维数组进行判断。
思路二:进行多次旋转,其实每个位置都可能会出现四个数中的任何一个数,其实就相当于我们把四个数随机放到四个格子中,那么我们可以不创建四个二维数组,我们把四个数存储,只需要创建一个二维数组,把四个数随机分配到里面即可。
遇到的问题以及解决方案:
第一个:数据的存储,我们采用二维数组来表示这个矩阵。
第二个:对于思路二中的随机分配,用一个简单粗暴的方法就是嵌套四个for循环
在这里我们给出思路一的代码(我才不会承认我比较懒不想写)
#include <stdio.h>
int main()
{
int a[2][2];
int b[2][2];
int c[2][2];
int d[2][2];
int i=0,g=0,h=0,n;
scanf("%d",&n);
for(i=0;i<n;i++){
scanf("%d %d",&a[0][0],&a[0][1]);
scanf("%d %d",&a[1][0],&a[1][1]);
d[1][0]=a[0][0];
c[1][1]=a[0][0];
b[0][1]=a[0][0];
d[0][0]=a[0][1];
c[1][0]=a[0][1];
b[1][1]=a[0][1];
d[0][1]=a[1][1];
c[0][0]=a[1][1];
b[1][0]=a[1][1];
d[1][1]=a[1][0];
c[0][1]=a[1][0];
b[0][0]=a[1][0];
if((a[0][0]<a[0][1]&&a[1][0]<a[1][1]&&a[0][0]<a[1][0]&&a[0][1]<a[1][1])||(b[0][0]<b[0][1]&&b[1][0]<b[1][1]&&b[0][0]<b[1][0]&&b[0][1]<b[1][1])||(c[0][0]<c[0][1]&&c[1][0]<c[1][1]&&c[0][0]<c[1][0]&&c[0][1]<c[1][1])||(d[0][0]<d[0][1]&&d[1][0]<d[1][1]&&d[0][0]<d[1][0]&&d[0][1]<d[1][1])){
printf("YES\n");
}
else printf("NO\n");
}
return 0;
}
这次比赛的A题也是个签到题,简直太容易了,就是让你写个加法没啥好说的,我们就直接跳过。
Dec/17/2022
题目解释:给出一个长度为n的序列 每一个元素代表一个塔,塔上有东西,元素的下标代表塔的序号,记作a1,a2,a3......an , 元素的数字代表塔上物品的多少,在1~n的范围内有ai和aj 如果ai>aj,那么可以从ai上拿一个给aj,这操作会使得ai少一个,aj多一个。那么在一系列操作之后,a1上最多有多少个东西?
我们再拿给是示例解释以下题目,例如第一组1 2 3 ,因为2>1,所以移动之后我们就是2,1,3然后因为3>2,所以我们在进行一次操作得到3,1,2此时的第一个塔等于3,已经是最大了,所以输出3,当然我们如果这么来看,一开始1,2,3,我们因为3>1,直接让他们进行操作变成2,2,2,之后便不能操作了,此时的2并非最大值。
那么问题来了,我们该如何确定怎么操作能最大呢?
既然要a1最大,那么a1要尽可能的多从别人那里获得,尽可能的多。
我们从刚刚第一组示例1,2,3来看看,我们想出了两个操作方法,为何第二个方法不行呢?我们来看看两者之间最后的值差1,不难看出,我们第二种方法让1,3直接操作,就导致了1操作完之后变成了2 直接丧失了与2的“求偶”机会,这就导致缺失了方法一中的1,2操作而增加的1,所以,我们是不是可以有这么一个想法:尽可能的增加操作次数,我们从小到大进行操作就可保证a1最后的值最大?
那么有了这个思路,我们就可以去试试,那题目所给的最后一组示例3,8,6,7,4,1,2,4,10,1
那么我们就是依次和4,6,7,8,10进行操作(当然,操作过程中可能会导致超过后面的某个数,直接跳过就行,我们只需要保证每次操作都是与可操作数里面最小的进行)最后结果的确是9,那么说明我们的想法有一定的可行性。有了想法,我们就可以动手操作。
遇到的问题及其解决方法:
一:我们既然要和最小的进行操作,那么怎么找到可操作数里面最小的?
解决方法:如果时间允许的话,每次操作前,你都可以遍历一次找最小的,这个想法也不是不可以。我的话,我最先想到的是先从小到大排序,之后就都不需要再去找最小的了。
二:操作之后的数量变化。这个是个不难的数学问题,相信应该都会。
所以最后我们的代码如下:
#include <stdio.h>
#include<math.h>
#include<stdlib.h>
int comp(const void*p,const void*q)
{
return *(int*)p-*(int*)q;
}
int main()
{
long long int g,m,a[200001]={0},b,i,t,n;
scanf("%lld",&m);
for(g=0;g<m;g++){
scanf("%lld",&n); //输入一个数n,表示接下来有n个数
for(i=0;i<n;i++){
scanf("%lld",&a[i]); //循环读入n个数到数组a中
}
b=a[0];
qsort(a,n,sizeof(long long int),comp);//快排 从小到大
for(i=0;i<n;i++){
if(a[i]>b){
b=ceil((a[i]+b)/2.0);
if(b>a[n-1]) break;
}
}
printf("%lld\n",b);
}
return 0;
}
特别注意:数组大小一定要大胆点给,我就是太小了,导致时间超限,掉大分,血的教训!!
今天的解析先到这里,如果有不对的,或者有更好思路的,欢迎大家在评论区讨论