滁州学院1024程序设计竞赛题解

滁州学院1024程序设计竞赛题解

受到语法的限制(就连数组都不能涉及太多),绝大部分的常用算法都无法考察,此次比赛更多的是对逻辑思维能力的锻炼。

A:信号转换器

签到题,直接模2即可。

#include <stdio.h>

int main(){
    
    int n;
    
    scanf("%d", &n);
    
    if(n % 2){
        printf("YES\n");
    }else{
        printf("NO\n");
    }
    
    return 0;
}

B:抽奖活动

简单的数位分离。多次循环,通过模10再除10分离出各个位置上的数字并求和,最后判断该数字模上它的数位和是否是0即可。

#include <stdio.h>

int main(){
    
    int n;
    
    scanf("%d", &n);
    
    //t是n的备份
    int t = n;
    //s用来记录各数位之和
    int s = 0;
    
    //数位分离
    while(t){
        s = s + (t % 10);
        t /= 10;
    }
    
    //判断n是否可以被s整除
    if(n % s){
        printf("no\n");
    }else{
        printf("yes\n");
    }
    
    return 0;
}

C:决战图书馆

博弈论入门题,通过简单的证明可以得知,当初始的石子数量为奇数时,alpha必胜,当初始的石子数量为偶数时,小轩必胜。证明过程如下:如果初始的石子数量为奇数,则不管小轩如何去分,都会产生一个奇数个数的石堆和一个偶数个数的石堆,此时Alpha可以扔掉奇数个数的石堆,将偶数个数的石堆分成两个奇数个数的石堆,这样不管小轩扔掉哪一个石堆,小轩的必然还剩下一个奇数的石堆,小轩继续(且必须)将奇数的石堆分成一个奇数的石堆和一个偶数的石堆,Alpha继续上一次的步骤。这样持续下去,到小轩分割石堆的时候,石堆必然有奇数个石子,因为石子是越分越少,最后小轩手上必然出现石堆中只有一个石子的情况,此时小轩无法分割,即alpha必胜。当初始的石子数量为偶数时,也可以使用相同的方法证明,这里不再赘述。

#include <stdio.h>

int main(){
    
    int n;
    
    scanf("%d", &n);
    
    //n组读入
    while(n--){
        int m;
        scanf("%d", &m);
        
        //模2为0 则ap wins
        if(m % 2){
            printf("ap wins\n");
        }else{
            //模2不为0 则xx wins
           printf("xx wins\n");
        }
    }
    
    return 0;
}

D:可口可乐

模拟+特判

#include <stdio.h>
 
int main(){
 
    int t;
    scanf("%d", &t);
 
    while(t--){
        int n, m;
        scanf("%d%d", &n, &m);
        //如果初始可乐数0 则一瓶都喝不到
        if(n == 0){
            printf("0\n");
        }else if(m <= 1){
            //如果0个或者1个空瓶就可以兑换一瓶新的可乐 则可以一直喝下去
            printf("Excited!\n");
        }else{
            //sum用来统计一共喝了多少瓶可乐 bottle用来记录当前空瓶子的数量
            int sum = n, bottle = n;
            //如果瓶子可以换就一直换下去
            while(bottle >= m){
                int t = bottle / m;
                sum = sum + t;
                bottle = bottle % m;
                bottle += t;
            }
            printf("%d\n", sum);
        }
    }
 
    return 0;
}

E:逃出生天

入门级线性DP(数字三角形模型),因为每次只能向上或者向左,所以我们定义一个状态为 dp[i][j] 表示能够到达 (i, j) 这个点的所有方案的能量最大值。所以动态转移方程为:dp[i][j] = arr[i][j] + max(dp[i+1][j], dp[i][j+1])。

#include <stdio.h>

int arr[1010][1010];
int dp[1010][1010];

int main(){
    
    int n;
    
    scanf("%d", &n);
    
    //读入整个地图
    for(int i = 1; i <= n; ++i){
        for(int j = 1; j <= n; ++j){
            scanf("%d", &arr[i][j]);
        }
    }
    
    //动态规划
    for(int i = n; i >= 1; i--){
        for(int j = n; j >= 1; j--){
            if(dp[i + 1][j] > dp[i][j + 1]){
                //从下面过来
                dp[i][j] = dp[i + 1][j] + arr[i][j];
            }else{
                //从右边过来
                dp[i][j] = dp[i][j + 1] + arr[i][j];
            }
        }
    }
    
    //输出结果
    printf("%d\n", dp[1][1]);
    
    return 0;
}

F:简单排序

签到题,因为只需要对三个数进行排序,所以只需手动模拟交换排序的核心过程即可。

#include <stdio.h>

int main(){
    
    int a, b, c;
    
    scanf("%d%d%d", &a, &b, &c);
    
    //如果a大于b  则a和b交换位置
    if(a > b){
        int t = a;
        a = b;
        b = t;
    }
    
    //如果a大于c 则a和c交换位置
    if(a > c){
        int t = a;
        a = c;
        c = t;
    }
    
    //如果b大于c 则b和c交换位置
    if(b > c){
        int t = b;
        b = c;
        c = t;
    }
    
    //输出结果
    printf("%d %d %d\n", a, b, c);
    
    return 0;
}

G:野餐

此题为防AK题,难度较大,看不懂的同学可以直接跳过,不做要求。考察的是多重背包问题的二进制优化(后台数据较大,多重背包的朴素解法会被卡掉)。

#include <stdio.h>
 
long long w[2010], cnt;
bool f[100010];
long long a[2010], s[2010];
int t, n, k;
int main(){
    
    scanf("%d", &t);
    
    //t组数据
    while(t--){
        //多重背包问题的二进制优化
        cnt = 1;
        scanf("%d", &n);
        for(int i = 1; i <= n; ++i){
            scanf("%lld", &a[i]);
        }
        for(int i = 1; i <= n; ++i){
            scanf("%lld", &s[i]);
        }
        scanf("%d", &k);
        //二进制优化 分解成01背包问题
        for(int i = 1; i <= n; ++i){
            int t = 1;
            while(t <= s[i]){
                w[cnt] = a[i] * t;
                cnt++;
                s[i] -= t;
                t = t * 2;
            }
            if(s[i] > 0){
                w[cnt] = s[i] * a[i];
                cnt++;
            }
        }
        n = cnt - 1;
        
        for(int i = 0; i <= 100010; ++i){
            f[i] = false;
        }
        
        //动态规划
        f[0] = true;
        for(int i = 1; i <= n; ++i){
            for(int j = k; j >= w[i]; --j){
                if(!f[j]){
                    f[j] = f[j-w[i]] ? true : false;
                }
            }
            if(f[k]){
                break;
            }
        }
        
        //输出结果
        if(f[k]){
            printf("Yes\n");
        }else{
            printf("No\n");
        }
    }
    return 0;
}

H:阶乘

循环计算出阶乘,然后数位分离再统计即可。阶乘的结果可能会炸int,必须用long long来存,考虑到大部分同学并没有学习到数组,这里展示不用数组的写法,用数组的话,代码会精简很多。

#include <stdio.h>

//用于存储0~9 各个数字出现的次数
int n0, n1, n2, n3, n4, n5, n6, n7, n8, n9;

int main(){
    
    int n;
    
    scanf("%d", &n);
    
    //20的阶乘会爆int 但是在long long的范围内 所以使用long long来存储
    long long ans = 1;
    
    //计算阶乘
    for(int i = 1; i <= n; ++i){
        ans = ans * i;
    }
    
    //数位分离
    while(ans){
        //对应的数字次数+1
        if(ans % 10 == 0){
            n0++;
        }else if(ans % 10 == 1){
            n1++;
        }else if(ans % 10 == 2){
            n2++;
        }else if(ans % 10 == 3){
            n3++;
        }else if(ans % 10 == 4){
            n4++;
        }else if(ans % 10 == 5){
            n5++;
        }else if(ans % 10 == 6){
            n6++;
        }else if(ans % 10 == 7){
            n7++;
        }else if(ans % 10 == 8){
            n8++;
        }else if(ans % 10 == 9){
            n9++;
        }
        ans /= 10;
    }
    
    //输出结果
    printf("%d %d %d %d %d %d %d %d %d %d\n", n0, n1, n2, n3, n4, n5, n6, n7, n8, n9);
    
    
    return 0;
}

I:优秀学生干部

循环读入,维护最大值即可。

#include <stdio.h>

using namespace std;

int n, t;

int main(){
    
    scanf("%d", &n);
    
    //ans初始化为-1 ans用来存储最高的票数  idx用来存储最高票数的编号
    int ans = -1, idx = 0;
    
    for(int i = 1; i <= n; ++i){
        scanf("%d", &t);
        //如果当前选手的票数比之前的所有人都高 则更新最大值
        if(t > ans){
            ans = t;
            idx = i;
        }
    }
    
    //输出结果
    printf("%d\n", idx);
    printf("%d\n", ans);
    
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值