2023年ggg二面题解

1.小鱼比可爱

洛谷P1428

单目鱼只会向左看,那就让每个鱼都去看一看它前面鱼是否比它可爱,用计数器计数即可

需要注意的是每条鱼计数完后需要将计数器重置为0

#include <stdio.h>
int main(){
    int n,i,j,count=0;   
    scanf("%d",&n); 
	int a[n];//若是使用标准c可以使用malloc为其分配内存
	for(i=0;i<n;i++){//外层循环给每一条鱼向左看的机会
		scanf("%d",&a[i]);   
      	for(j=0;j<i;j++){//内层循环让每条鱼都能扫视它前面所有的鱼
			if(a[i]>a[j]){
              	count++;
           	}    
      	}
    	printf("%d ",count);
     	count=0;
    	}
	}
    return 0;
}

2.素数回文数的个数

洛谷B2136

此题突破两点即可,一是素数,二是回文数

素数:除了1和它本身没有别的因子☞遍历2到该数前一个数(提高效率可以只遍历到其平方根)作为除数,挨个判断即可

回文数:正着看和倒着看一样☞直接求其反过来的值与原值对比即可

#include<stdio.h>
#include<math.h>
int judge1 (int a)//判断素数
{
    int i;
    if(a%2==0)return 0;//提高效率
    for(i=2;i<sqrt(a);i++){
       if(a%i==0){
       	return 0;
       }
    }
    return 1;}
int judge2(int a)//判断回文数
{
    int r=0,temp=a;
    while(a){
        r=r*10+a%10;
        a/=10;
    }
    if(r==temp){
       return 1;
    }
    else return 0;
}
int main ()
{
    int a=0,n;
    scanf("%d",&n);
    for(int i=11;i<=n;i++){
        if(judge(i)&&judge2(i)){
           a++;
        }
    }
    printf("%d\n",a);
    return 0;
}

3.开关灯

洛谷B2092

开和关是两种状态,正巧二进制也只有0和1两个数,所以很自然地就能联想到当将开设为1,关设为0的操作

#include <stdio.h>
int main(){
    int n,i,j,k;
    scanf("%d",&n);
    int a[n];
    for(i=0;i<n;i++){
        a[i]=0;
    }//第一个人将灯全部关闭
    for(i=1;i<n;i+=2){
        a[i]=1;
    }//第二个人将灯全部打开
    for(i=3;i<=n;i++){//控制第n个人
        for(j=i-1;j<n;j+=i){//让第n个人去其倍数的灯做相反操作
            if(a[j]==1)a[j]=0;
            else a[j]=1;
        }
    }
    for(k=0;k<n;k++){
        if(a[k]==0)printf("%d ",k+1);
    }//灯和数组里的存储差了1,需要需要加1
    return 0;
}

4.确定进制

洛谷B2141

  • 先确定大体思路:将需要测试的进制全部从小到大遍历一遍,如果过程中找到第一个使条件成立的就退出循环,如果遍历完了仍然没能退出循环,就说明不存在符合的进制输出0

    好处:可以直接找到最小的进制,不用作比较

  • 遍历过程需要注意的一点:需要测试的进制不一定都要从2开始,需要确定三个数最小能存在的进制

    举个例子:31,5,96☞进制只能从10开始遍历,因为10以下的进制不存在9这个数的表达

  • 10进制转化为b进制,即将其n位分别*bn-1次方

  • 在转化的过程中可能会出现数值过大导致无法过所有测试点的情况,所以通篇采用了long long int的定义

#include <stdio.h>
long long int zhuanhua(long long int n,long long int b){
    long long int sum=0;
    long long int i,j=0;
    while(n>0){
        long long int m=n%10;//每轮分离出每次的个位
        n/=10;
        for(i=1;i<=j;i++){
            m*=b;
        }//该步也可以用math.h库中的pow函数替代
        sum+=m;
        j++;
    }
    return sum;
}//将10进制数转化为b进制数
long long int judge(long long int p,long long int q,long long int r,long long int b){
    if(p>=b)p=zhuanhua(p,b);
    if(q>=b)q=zhuanhua(q,b);
    if(r>=b)r=zhuanhua(r,b);
    if(p*q==r)return 1;
    else return 0;
}//将p,q,r转化后判断其是否满足表达式
long long int maxn(long long int i){
    long long int p=i;
    long long int max=0;
    for(long long int j=0;p>0;j++){
        i=p%10;
        p/=10;
        if(i>max)max=i;
    }
    return max;
}//找一个数各位最大的数
int main(){
    long long int p,q,r;
    long long int i;
    scanf("%lld %lld %lld",&p,&q,&r);
    long long int max;
    long long int a=maxn(p),maxn=n(q),maxn=n(r);
    if(a>=b&&a>=c)max=a;
    if(b>=a&&b>=c)max=b;
    if(c>=a&&c>=b)max=c;
    //此处找到三个数各位最大的数
    for(i=max+1;i<=16;i++){ 
        if(judge(p,q,r,i)){
        	printf("%lld",i);
            break;
        }
        if(i==16)printf("0");//遍历完了都没找到,即不存在
    }
    return 0;
}

5.拼数

洛谷P1012

  1. 初版思路的实现与更新:

    直接将各个数以整型去比较会很麻烦,如果是以字符串去比较则很简单,strcmp函数完美地满足了题目的需求,但是需要结合循环不断地比较,实际实现起来又会陷入新的麻烦

    所以采用qsort函数,用qsort去直接对字符串进行比较并排序,将对应的cmd函数用strcmp改造即可

  2. 读取数据时的问题:

    如果直接读入字符串也会很麻烦,因为各个数据输入在一行,而scanf(%s)gets等等都会直接读取完一行,所以先以整型读入,再用sprintf函数将其转化为字符串

  3. 各个函数的作用:

  • sprintf""内读入的内容以字符串的形式读进数组(数组名,格式化控制字符,需要读入的具体内容)
  • strcmp接受两个字符串,从左往右进行两个字符串的各个字符比较,直接遇到不一样的为止(串1,串2)
  • qsort将对应的比较函数进行改造,可以比较各种类型的数据(要排序的数组,需要排序的元素个数,一个元素的大小,比较函数),详细介绍请查阅其他资料

于是初版代码得以实现:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int cmd(const void* a,const void* b){
    return strcmp((char*)b,(char*)a);
}
int main(){
    int n;
    scanf("%d",&n);
    char str[n][10];
    int a[n];
    for(int i=0;i<n;i++){
        scanf("%d",&a[i]);
        sprintf(str[i],"%d",a[i]);
    }
    
    int t=sizeof(str)/sizeof(str[0]);
    qsort(str,t,sizeof(str[0]),cmd);
    for(int i=0;i<n;i++){
        printf("%s",str[i]);
    }
    return 0;
}

但是交上去只有75分,说明大体思路没问题

查看测试点会发现一个很巧妙的点,将32321进行排序的时候,按照上面排序的逻辑排下来是32132,但这显然没有32321大,所以需要进一步改变比较的逻辑

既然不能只看单个字符串间的比较,那直接将它们拼接后的结果进行比较就好了,问题得以解决,修改代码如下

补充下面的两个字符串函数注解:

  • strcpy接受两个字符串,将第一个字符串清除,随后第二个字符串到第一个字符串上(串1,串2)
  • strcat接受两个字符串,将第二个字符串接到第一个字符串上(串1,串2)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int cmd(const void* a, const void* b) {  
    char ma[20], mb[20];   
    strcpy(ma, (char*)a);  
    strcpy(mb, (char*)b);  
    char *m = strcat(ma, mb);  
    char *n = strcat(mb, ma);  
    return strcmp(n,m);  
}  
int main(){
    int n;
    scanf("%d",&n);
    char str[n][10];
    //用二维数组来储存多个字符串
    int a[n];
    for(int i=0;i<n;i++){
        scanf("%d",&a[i]);
        sprintf(str[i],"%d",a[i]);
        //sprintf函数可以将“”内的内容以字符串的形式储存到str中
    }
    int t=sizeof(str)/sizeof(str[0]);
    qsort(str,t,sizeof(str[0]),cmd);
    //按首字符大小进行排序
    for(int i=0;i<n;i++){
        printf("%s",str[i]);
    }
    return 0;
}

6.高精度减法

洛谷P2142

  • 为什么要用高精度以及第一步:存:

我们知道,当数的范围超过了long long int就会爆掉,这时就需要请出我们的高精度,本题正是如此

整型存放不下,就只能用数组去存了,而在读入时如果读到整型数组里面又会爆掉,不得不用字符串数组了

当然毕竟是数的运算,所以字符串数组接受后还是需要转化为整型存入数组的,字符-'0'可以轻松实现转化

  • 第二步:倒

竖式运算的核心在于位数要对齐,而正着存入数组时显然没有做到这一点,所以需要倒着放进去

在实际代码的实现中,一二步其实时一起进行的

for(i=0;i<n1;i++){
	a[i]=str1[n1-i-1]-'0';
}
for(i=0;i<n2;i++){
	b[i]=str2[n2-i-1]-'0';
}
  • 核心思想:

    高精度减法其实就是小学数学竖式运算,原理也来源于此,即该位减不过时向上一位借1,同时本位加10

  • 第三步:减

该步实现具体的竖式运算,当被减数的本位小于减数时借位即可,借位也要有位可借才行,所以通常以大减小,

以小减大的情况将在后文讨论

for(int i=0;i<n;i++){
	if(a[i]<b[i]){
		a[i]+=10;
		a[i+1]-=1;
	}
	a[i]-=b[i];
}
  • 第四步:输出

在输出结果之前,首先需要清除前导0,

举个例子:123-123,按上面的方法算下来应该时000,这明眼人一看就知道这结果有问题,所以就需要清除多余的0,而为了不清掉最后一个0还需要加一个n>0的限制条件

while(a[n]==0&&n>0){
	n--;
}
while(n>=0){
	printf("%d",a[n]);
	n--;
}

到这里大体思路其实已经完成了,但还需要处理一些细节问题:

  • 如果被减数小于减数怎么办?

    • 所以在第一步的时候应该做一些特殊处理,在存入整型数组的时候先判断两数大小,字符串的一堆函数就注定了这个判断是要在存入之前进行,strcmp函数真的很好用,比较一下两个字符串

    • 但这个时候又蹦出来一个问题,56123这种比较不就又出事了,所以还需要加入判断两个字符串长度的条件比较

    • 当然,不能忘了输出负号,更改一下倒序输出的逻辑,以确保最终输出是大减小可以借位的情况下进行,不然会出现10-20=-9的奇观

各部分解析完成,整体代码如下:

#define t 1000010
int main(){
	char str1[t],str2[t];
    scanf("%s%s",str1,str2);
    int a[t]={0},b[t]={0};
    int n1=strlen(str1),n2=strlen(str2);
    int n=n1;
    if(n<n2){
        n=n2;
    }
    if((n1==n2&&strcmp(str1,str2)>0)||n1>=n2){
        for(int i=0;i<n1;i++){
            a[i]=str1[n1-1-i]-'0';
        }
        for(int i=0;i<n2;i++){
            b[i]=str2[n2-1-i]-'0';
        }
    }
    else{
        for(int i=0;i<n2;i++){
            a[i]=str2[n2-1-i]-'0';
        }
        for(int i=0;i<n1;i++){
            b[i]=str1[n1-1-i]-'0';
        }
        printf("-");
    }
    for(int i=0;i<n;i++){
        if(a[i]<b[i]){
            a[i]+=10;
            a[i+1]-=1;
        }
        a[i]-=b[i];
    }
    while(a[n]==0&&n>0){
        n--;
    }
    while(n>=0){
        printf("%d",a[n]);
        n--;
    }
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
解题思路如下: 对于2023年国赛C题,我们可以按照以下步骤来解决问题: 1. 第一问: 首先,需要根据题目所给的数据和条件进行合理的建模。可以使用MILP模型来求解问题二,并根据销售空间及最小陈列量进行相应的限制。在求解阶段,可以设计0编码机制来适应销售空间限制,并通过修复机制保持染色体的合法性。另外,可以利用问题二中构建的动态调整模型进行调价决策。 2. 第二问: 对于问题二,需要分析各种类蔬菜的销售总量与成本加成定价之间的关系。可以建立集成拟合模型来拟合每种蔬菜单品的销量与成本利润率之间的关系。然后,根据成本利润率来确定销量,并给出每种蔬菜品类未来一周的日补货总量和定价策略。可以构建以最大化商超收益为目标的混合整数线性规划模型,并使用遗传算法对模型进行求解。 3. 第三问: 针对问题三,需要分析蔬菜各品类及单品销售量的分布规律及相互关系。可以从三个角度进行剖析: a) 各种类蔬菜的销售量分布和蔬菜种类与销售量之间的关系;b) 各种类蔬菜的销售量的月份分布和各种类蔬菜销售量与月份之间的相关关系;c) 各种类蔬菜的销售时间分布和销售时间与退货量之间的相关关系。可以利用箱线图和折线图来描述销量的分布特征,使用Kolmogorov-Smirnov分布检验来验证分布的一致性,并进行相关性分析来计算相关系数。 以上是解决2023年国赛C题的一些思路和方法。希望对您有所帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值