官网省赛题解析

1、规范思考题(细心就能AC)

(1)回文日期 合法日期+回文判断

给定一个 8 位数的日期,请你计算该日期之后下一个回文日期和下一个 ABABBABA 型的回文日期各是哪一天。
【输入】一个八位整数 N表示日期(10000101≤N≤89991231)保证 N 是一个合法日期的 8 位数表示。
【输出】两行每行 1 个八位数。第一行表示下一个回文日期,第二行表示下一个 ABABBABA 型的回文日期。
思路: 首先判断是否为合法日期(平闰年+月份),再判断是否回文。

int a,b,c,d,e,f,g,h;
bool islegal(){ //合法日期
    int y=h*1000+g*100+f*10+e;
    int m=d*10+c;
    int d=b*10+a;
    if (m==1||m==3||m==5||m==7||m==8||m==10||m==12){ //1 3 5 7 8 10 12月
        if (d>0 && d<32) return true;
        else return false;
    }
    if (m==4||m==6||m==9||m==11){//4 6 9 11月
        if (d>0 && d<31) return true;
        else return false;
    }
    //平闰年
    int run;
    if (y%100==0){
        if (y%4==0) run=1;
        else run=0;
    }
    else{
        if (y%4) run=1;
        else run=0;
    }
    //二月单独判断
    if (run && m==2 && d>0 && d<=29) return true;
    else if (!run && m==2 && d>0 && d<29) return true;
    else return false;
}
int main(){
    int n,f1=1,f2=1;
    cin>>n;
    while (f1 || f2){
        n+=1;
        //提取每个数字
        a=n%10;
        b=(n/10)%10;
        c=(n/100)%10;
        d=(n/1000)%10;
        e=(n/10000)%10;
        f=(n/100000)%10;
        g=(n/1000000)%10;
        h=(n/10000000)%10;
        if (islegal()){ //合法日期
            if (a==h && b==g && c==f && d==e){//回文
                if (f1){
                    f1=0;
                    cout<<n<<endl;
                }
                if (a==c && b==d){//ABABBABA
                    f2=0;
                    cout<<n<<endl;
                }
            }
        }
    }
  return 0;
}

(2)跑步锻炼 平闰年+1号+星期1判断

正常情况下小蓝每天跑1km,如果某天是周一或月初(1日), 小蓝要跑2千米。如果同时是周一或月初,小蓝也是跑2千米。从2000年1月1日周六(含)到 2020年10月1日周四(含)。请问这段时间小蓝总共跑步多少千米?
思路: 数组存储每月天数,int存储当前月份、星期,从2000.1.1到2020.10.1遍历,仔细判断。

int main(){
    int month[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
    int sum=0,day=6;
    for (int i=2000;i<2021;i++){
        //平润年2月天数不同
        if (i%4==0) month[2]=29;
        else month[2]=28;

        int maxi,nowM=1,cnt=1;//最大月份,1月,1日
        int run; //每天跑多少
        if (i!=2020) maxi=13;
        else maxi=10;
        while (nowM<maxi){
            while (cnt<=month[nowM]){//每个月
                run=1;
                if (day==8) day=1;//换星期
                if (cnt==1||day==1) run=2;//1号或星期1
                cnt+=1;
                day+=1;
                sum+=run;
            }
            cnt=1;
            nowM+=1;
        }
    }
    cout<<sum+2; //10月1日肯定跑2km
    return 0;
}

2、数学思考题(啊这啊这 没有脑袋怎么办)

(1)空间 计科人常识题

小蓝准备用 256MB的内存空间开一个数组,数组的每个元素都是 32位 二进制整数,如果不考虑程序占用的空间和维护内存需要的辅助空间,请问 256MB的空间可以存储多少个 32位二进制整数?
思路: 32位二进制为4个字节(4B),答案为256 * 1024 * 1024/4

(2)蛇形填数 找规律

在这里插入图片描述
思路: 只看主对角线,(1,1)=0+1,(2,2)=1+4,(3,3)=4+9…
(20,20)=19 * 19+20 * 20=761

(3)即约分数 最大公因数板子题

在这里插入图片描述

int gcd(int x,int y){return y?gcd(y,x%y):x;};
int main(){
    int cnt=4039; //分子或分母为1
    for (int i=2;i<2021;i++){
        for (int j=2;j<2021;j++){
            if (gcd(i,j)==1) cnt+=1;
        }
    }
    cout<<cnt;
    return 0;
}

(4)排序 了解冒泡复杂度

在冒泡排序中,每次只能交换相邻的两个元素,如果对一个字符串中的字符排序,只允许交换相邻的两个字符, 则在所有可能的排序方案中,冒泡排序的总交换次数是最少的。
例如,对于字符串 lan排序,只需要 11 次交换。对于字符串 qiao排序,总共需要 44 次交换。
请帮助小蓝找一个只包含小写英文字母且没有字母重复出现的字符串,对该串的字符排序,正好需要 100次交换。如果可能找到多个,请告诉小蓝最短的那个。如果最短的仍然有多个,请告诉小蓝字典序最小的那个。
思路: 冒泡排序最多需要交换N*(N-1)/2次(完全乱序时)N=15时有15* 14/ 2=105,即满足100次交换所需的最短字符串有15个字母。
要求字典序最小,那么显然要取a~o这15个字典序最小的字母。逆向思考,目标字符串经过100次交换后,得到正序字符串abcdefghijklmno,而完全逆序的字符串onmlkjihgfedcba变成正序字符串需要105次交换,那么将完全逆序的字符串交换5次后,便能得到答案。
而要求字典序最小,那么将j交换5次提到字符串最前面,就得到了最小的情况:“jonmlkihgfedcba”

3、数据结构及算法(自信觉得我可以)

(1)数字三角形 动态规划

在这里插入图片描述
从三角形的顶部到底部有很多条不同的路径,把路径上面的数加起来可以得到一个和,你的任务就是找到最大的和。路径上的每一步只能从一个数走到下一层和它最近的左边的那个数或者右 边的那个数。此外,向左下走的次数与向右下走的次数相差不能超过 1。
【输入】
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
【输出】
27
思路: 第一遍用了+条件的dfs,结果循环超时了TAT

#include <cmath>
#define maxn 100
int sum=0,n;
int road[maxn][maxn];
void dfs(int i,int j,int num,int left,int right){
    if (i==n-1){//走到底了
        if (num>sum && abs(left-right)<2) sum=num; //符合条件的
        return;
    }
    if (j>i || i>=n) return; //没有路
    dfs(i+1,j,num+road[i+1][j],left+1,right);
    dfs(i+1,j+1,num+road[i+1][j+1],left,right+1);
}
int main(){
    cin>>n;
    for (int i=0;i<n;i++){
        for (int j=0;j<=i;j++) cin>>road[i][j];
    }
    dfs(0,0,road[0][0],0,0);
    cout<<sum;
    return 0;
}

看答案要用动态规划,努力学习dp ing
c[1][1]=a[1][1]
c[i][j]=a[i][j]+max(c[i-1][j-1] ,c[i-1][j])

#define maxn 100
int a[maxn][maxn],c[maxn][maxn],n;
int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=i;j++) cin>>a[i][j];
    }
    c[1][1]=a[1][1];
    for(int i=2;i<=n;i++){
        for(int j=1;j<=i;j++) c[i][j]=a[i][j]+max(c[i-1][j],c[i-1][j-1]);
    }
    cout<<max(c[n][(n+1)/2],c[n][(n+2)/2]);
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值