考试的题,太惨了

本文包含三个算法问题的解决方案:一是寻找n个非负整数的最大中位数之和;二是利用前缀和处理大范围数列查询;三是找到两个质数和为s时的最大乘积。此外,还涉及将N进制数反转并求解回文数的最少步骤问题。这些问题涵盖了数值计算、质数筛选和数组操作等算法知识。
摘要由CSDN通过智能技术生成

求n个和为s的非负整数的最大中位数,巨简单,结果没看懂题

#include<bits/stdc++.h>
using namespace std;
int t,s,z,ans;
double n;
int main()
{
    scanf("%d",&t);
    for(int i=1;i<=t;i++)
    {
        scanf("%lf%d",&n,&s);
        z=ceil(n/2);  //  求出中位数是排第几的数,注意z一点要开long long,这样才能用向上取整函数
        ans=s/(n-z+1);  //  要求和不变而中位数最大,就要让中位数前面的数尽量小,都等于0,然后让中位数尽可能接近剩下的数的平均数,用s除以剩下的数,因为自动向下取整所以不用担心有偏差
        printf("%d\n",ans);  //  然后就完了,真的简单啊
    }
    return 0;
}

---------------------------------------------------------------------------------------------------------------------------------

L 偶然发现了一个数列 a 1 , a 2 . . . a n ,但是他对这些数不感兴趣,所以他把这个数列告诉你了。但 是他又对这个数列念念不忘,所以他又会经常来询问你,每次询问会告诉你一个 l 和一个 r ,请你告诉他 满足 l a i r 的元素有多少个。
本来没啥事,但是因为数据范围太大,开到了1e5,会超时,所以要用前缀和来写

#include<bits/stdc++.h>
using namespace std;
const int N=100005;
int n,q,aa,ans=0,l,r;
int a[2*N],s[N*2];
int main()
{
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&aa);
        aa+=N;  //  a是读进来的数,为了防止有负数所以全部加上一个很大的数N
        a[aa]++;  // 该数的数量加一,用的是桶排
    }
    s[0]=0;
    for(int i=1;i<2*N;i++)  //  注意,这里要算的前缀和下标范围是整个数据范围,就是2N
    {
        s[i]=s[i-1]+a[i];  //  第i个前缀和等于第i-1个前缀和加上i的数量
    }
    for(int i=1;i<=q;i++)
    {
        ans=0;
        scanf("%d%d",&l,&r);
        l+=N;   //  前面都加了N,所以这里的范围也要加N
        r+=N;
        ans=s[r]-s[l-1];  //  l到r范围内的数等于第r个前缀和减去第l-1个前缀和,可以自己推理一下得到
        printf("%d\n",ans);
    }
    return 0;

---------------------------------------------------------------------------------------------------------------------------------

如果两个质数的和为 s,那么他们的乘积最大值是多少

#include<bits/stdc++.h>
using namespace std;
int s,a,b;
long long m=1,n=0;  //   乘积要开long long ,因为数据范围给到了1e5,int会爆
int k=1;
int z[2000000];
bool tf=true;
int main()
{
    scanf("%d",&s);
    for(int j=2;j<=s;j++)  //  先找出s以内的质数,这样复杂度小一点
    {
        tf=true;
        for(int i=2;i*i<=j;i++)
        {
            if(j%i==0)
            {
                tf=false;
                break;
            }
        }
        if(tf==true)
        {
            z[k]=j;
            k++;
        }
    }
    for(int a=1;a<k;a++)  //  然后暴力枚举,如果相加等于s,就算出他们的乘积
    {
        for(int b=1;b<k;b++)
        {
            if(z[a]+z[b]==s) m=1ll*z[a]*z[b];
            if(m>n) n=m;   //  用n找出最大的乘积
        }
    }
    printf("%lld",n);  //  输出,记得是lld
    return 0;

---------------------------------------------------------------------------------------------------------------------------------

给定一个 N 进制正整数,把它的各位数字上数字倒过来排列组成一个新数,然后与原数相加,如果 是回文数则停止,如果不是,则重复这个操作,直到和为回文数为止。
给定一个 N 进制数 m 10 15 用小写字母 a f 表示), m 的位数上限为 20 。求最少经过几步可以得到回文数。如果在 30 步以内(包括 30 步)不可能得到回文数,则输出“ impossible ”,否则输出该回文数及生成该回文数的最少步数。
这题就有点离谱了

#include<bits/stdc++.h>
using namespace std;
int n,k,lenmz,lenmf,lenc,ans=0;
char m[800];
char a;
int c[800],mf[800],mz[800];
bool tf;
int hw(int a[],int lena)  //  写一个判断回文数的函数,往函数里传数组用的是int a[]的形式,同时要把长度传进去
{
    int i=0;
    tf=true;
    lena--;  //  数组从零开始,所以长度要减一才是最后一位数的下标
    while(i<lena)
    {
        if(a[i]!=a[lena]) //  看最后一位和第一位的数字是否相等,不相等就不是回文数,可以停止循环,否则前后都往中间推进,继续进行比较
        {
            tf=false;
            break;
        }
        else 
        {
            i++;
            lena--;
        }
    }
    if(tf==true) return 1;
    else return 0;
}
int main()
{
    cin>>n;
    scanf("%s",m);  //   先以字符串的形式读入这个数字
    lenmz=strlen(m);  //  得到他的长度
    lenmf=lenmz;
    memset(c,0,sizeof(c));
    memset(mf,0,sizeof(mf));
    memset(mz,0,sizeof(mz));
    for(int i=0;i<lenmf;i++)
    {
        if(m[i]>='0'&&m[i]<='9') mz[i]=m[i]-'0';  //  先处理10以内的数字
        else mz[i]=m[i]-'a'+10;  //因为10以上的数字以字母的形式出现,所以减去a的编码,然后加20让他成为一个两位数
    }
    if(hw(mz,lenmz)==1)  //  引用上面写的函数,判断他是不是回文数,如果自己本身不是回文数才要进行后面的操作
    {
        for(int i=0;i<lenmf;i++)
        {
            printf("%d",mz[i]);
        }
        printf("\n0");
    }
    else while(hw(mz,lenmz)!=1)  
    {
        memset(c,0,sizeof(c));
        memset(mf,0,sizeof(mf));
        ans++;  //如果不是回文数,操作次数加1
        for(int i=0;i<lenmz;i++)
        {
            mf[i]=mz[lenmz-i-1];  //  把他倒过来,然后进行高精加
        }
        lenc=0;
        k=0;
        while(lenc<lenmz)
        {
            c[lenc]=mz[lenc]+mf[lenc]+k;
            k=c[lenc]/n; 
            c[lenc]%=n;
            lenc++;
        }
        ++lenc;  //  位数相等时就停下了,可能在更高位上有进位
        c[lenc-1]=k;
        if(k==0) lenc--;  //  如果最高位是0,删除最高位
        for(int i=0;i<lenc;i++)
        {
            mz[i]=c[i];  //  再把加完的结果给回原来的数组
        }
        lenmz=lenc;
        if(ans>30) break;  //  操作次数大于30时马上停止,后面的操作没有意义了
    }
    if(ans<=30&&ans!=0)
    {
        for(int i=0;i<lenmz;i++)
        {
            if(mz[i]<=9) printf("%d",mz[i]);  //  输出得到的最小回文数
            else putchar('a'+mz[i]-10);  //  大于10的数要用字符形式输出,原来-'a'+10,现在还原回去就是+'a'-10
        }
        printf("\n%d",ans);  然后输出操作次数
    }
    else printf("impossible");  //  不然输出给定字符
    return 0;
}

总结:首先吧,考试要记得写文件输入输出,血的教训,然后要自己算一下复杂度,超时就完蛋,注意细节,要学会知识的迁移,不要把简单的东西复杂化,函数内传数组不需要写下标值域,还要算一下数据范围,看int会不会爆,不要老是忘long long,记得向上取整函数只对double有用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值