2020 BNUZ 新生现场赛 题解

131 篇文章 0 订阅
3 篇文章 0 订阅

组合技

此题将n-1个元素加1可以等价于
每次让1个元素-1,多少次后所有元素相等

#include <stdio.h>

int main() {
    int t, n;
    int num[1010];
    scanf("%d", &t);
    for (int i = 1; i <= t; i++) {
        scanf("%d", &n);
        int sum = 0;
        int min = 100;
        for (int j = 0; j < n; j++) {
            scanf("%d", &num[j]);
            sum += num[j];
            if (min > num[j]) {
                min = num[j];
            }
        }
        printf("Case #%d:\n%d\n", i, sum - min * n);
    }
}

站好队

简单dfs

题意为把k个学生放到方形队伍中,这些学生不能同一行也不能同一列,问有多少种结果

具体可看注释

#include<stdio.h>
#include<string.h>

//把cb,cbc,ans,n,k弄成全局变量,方便在dfs中使用
char cb[100][100];
int cbc[100];
long long ans = 0;
int n, k;

void dfs(int x, int y)//x是行数,y是学生数
{
    if (k == y) {//当学生数达到要求时
        ans++;
        return;
    }
    for (int i = x; i < n; i++) {
        //因为题目要求不能同一行,所以从x开始往下扫描
        for (int j = 0; j < n; j++) {
            //不能同一列,用数组cbc来存结果
            if (cb[i][j] == '#' && cbc[j] == 0) {
                //如果有过了这一列了,就用让cbc=1,等到这次递归完成,再改回0
                cbc[j] = 1;
                dfs(i + 1, y + 1);
                cbc[j] = 0;
            }
        }
    }
}

int main() {
    int t;
    scanf("%d", &t);
    for (int q = 1; q <= t; q++) {
        scanf("%d %d", &n, &k);
        memset(cbc, 0, sizeof(cbc));//使数组全部为0
        getchar();
        for (int i = 0; i < n; i++) {
            gets(cb[i]);
        }
        ans = 0;
        dfs(0, 0);
        printf("Case #%d:\n%lld\n", q, ans);
    }
}

我不看月亮

就是看摸鱼和放回鱼的数量,如果已经到了0就不减

代码:

#include<stdio.h>
#include<string.h>

int main() {
    int t, n;
    char cb[1000000];
    int ans[101];
    memset(ans, 0, sizeof(ans));
    scanf("%d", &t);
    for (int i = 1; i <= t; i++) {
        scanf("%d", &n);
        scanf("%s", cb + 1);

        for (int j = 1; j <= n; j++) {
            if (cb[j] == 'c') {
                if (ans[i] > 0) {
                    ans[i]--;
                }
            } else {
                ans[i]++;
            }
        }
    }
    for (int i = 1; i <= t; i++) {
        printf("Case #%d:\n%lld\n", i, ans[i]);
    }
}

记忆大王李华

#include<stdio.h>
#include<stdlib.h>

//该公式中把一月和二月看成是上一年的十三月和十四月

int main(void)
{
	int year, month, day;
	int d1[13] = {31,28,31,30,31,30,31,31,30,31,30,31};
	int d2[13] = {31,29,31,30,31,30,31,31,30,31,30,31};
	int cas = 1;
	while(~scanf("%d %d %d", &year, &month, &day)){
		getchar();
		int sum = 0;
		if((year<=0 || year>=10000)||(month<=0 || month>=13)||(day<=0||day>=32)){
			continue;
		}
		if((year%100!=0 && year%4==0)||year%400==0){
			for(int i = 0; i < month-1; i++){
				sum += d2[i];
			}
		}
		else{
			for(int i = 0; i < month-1; i++){
				sum += d1[i];
			}
		}
		sum+=day;
		for(int i = 1; i < year; i++){
			if((i%100!=0 && i%4==0)||i%400==0)
			sum+=366;
			else
			sum+=365;
		}
		printf("Case #%d:\n",cas++);
		int x = sum % 7;
		switch(x){
			case 0:
				printf("Sunday\n");
				break;
			case 1:
				printf("Monday\n");
				break;
			case 2:
				printf("Tuesday\n");
				break;
			case 3:
				printf("Wednesday\n");
				break;
			case 4:
				printf("Thursday\n");
				break;
			case 5:
				printf("Friday\n");
				break;
			case 6:
				printf("Saturday\n");
				break;
		}
	}
	return 0;
}

小彩蛋
部分题目名的典故

后海有树的院子,夏代有工的玉,此时此刻的云,二十来岁的你。

为什么乌鸦像写字台——就像我喜欢你,没有理由

我不看月亮,也不说想你,这样月亮和你都蒙在鼓里

人们从诗人的字句里 选取自己心爱的意义 但诗句最终意义是指向你

我想要在茅亭里看雨、假山边看蚂蚁,看蝴蝶恋爱,看蜘蛛结网,看水,看船,看云,看瀑布,看宋清如甜甜地睡觉

世间情动,不过盛夏白瓷梅子汤,碎冰碰壁当啷响

要和你秉烛夜游,要和你一醉方休;
要与你听风轻雨柔,要与你游山清水秀;
要为你采了莲叶熬粥 要为你摘了桂花酿酒;
这一生,怎么够?

用来签到的打牌游戏

本题的重点是思路思路思路

无非就是摸牌摸起来升序。想象着有个摄像机拍摄你摸牌的过程:摸了一张,放了一张到末尾(牌堆底部),一直循环这个过程直到摸完。你手上有了一个升序的牌组
现在开始倒放步骤一提到的录像。画面显示:你从升序的牌组中拿了一个最大的(你在步骤一中最后放进牌组的牌),放到了桌上;把末尾的牌放到最开始的位置(牌堆顶),如果桌上没有牌或者只有一张牌则直接放牌。普遍的过程变成了:放一张到开始位置(牌堆顶部),放一张牌
converse函数是“放一张到顶部”,set是“从手上放一张牌下去”,排序后的desk数组就是手里的牌。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int Cmp(const void* a, const void* b)
{
    return *(int*)a - *(int*)b;
}
void converse(int* ret, int q)
{
    if (q == 0) {
        return;
    }
    int temp = ret[q - 1];
    for (int i = q - 1; i > 0; i--) {
        ret[i] = ret[i - 1];
    }
    ret[0] = temp;
    return;
}
void set(int* ret, int q, int tag)
{
    for (int i = q - 1; i > 0; i--) {
        ret[i] = ret[i - 1];
    }
    ret[0] = tag;
    return;
}
int* deckRevealedIncreasing(int* deck, int deckSize)
{
    qsort(deck, deckSize, sizeof(int), Cmp);
    int* ret = (int*)malloc(deckSize * sizeof(int));
    memset(ret, 0, deckSize * sizeof(int));
    int q = 0;
    for (int i = deckSize - 1; i >= 0; i--) {
        converse(ret, q);
        q++;
        set(ret, q, deck[i]);
    }
    /**returnSize = q;*/
    return ret;
}
int main() {
    int n;
    int a[1000000];
    int* c;
    int t;
    while (~scanf("%d",&t)){
        int j = 0;
        for (int i = 0; i < t; i++) {

            scanf("%d", &n);
            for (int i = 0; i < n; i++) {
                scanf("%d", &a[i]);
            }
            c = deckRevealedIncreasing(a, n);
            j++;
            printf("Case #%d:\n", j);
            for (int i = 0; i < n; i++) {
                if (i == n - 1)
                    printf("%d ", c[i]);
                else
                    printf("%d ", c[i]);
            }
            printf("\n");
        }
    }
    return 0;
}

你会看天气预报吗

暴力,直接遍历一遍,然后判断输出即可

#include<stdio.h>
#include<string.h>
int main()
{
	int t;
	int cb[1001];
	scanf("%d",&t);
	for(int i = 1; i <= t; i ++){
		int n;
		scanf("%d",&n);
		for(int j=0 ; j<n ;j++){
			scanf("%d",&cb[j]);
		}
		printf("Case #%d:\n",i);
		for(int j=0; j<n ; j++){
			for(int k=j ; k<n ; k++){
				if(cb[j]<cb[k]){
					printf("%d ",k-j);
					break;
				}
				if(k==n-1){
					printf("0 ");
				}
			}
		}
		printf("\n");
	}
}

小明的派对

数量较少,直接暴力
想用一个数组存男生在L-R时间段里的人数(数组的数目表示今天能参加的男生数)

同理将女生的存起来

最后找到366天每一天男女参加人数的最小值的两倍,然后取出其中的最大值即可。

#include<stdio.h>
#include<string.h>
int cb[2][1000];
int min(int a,int b){
	if(a<b)return a;
	return b;
}
int main()
{
	int t;
	scanf("%d",&t);
	for(int i = 1; i <= t; i ++){
		memset(cb,0,sizeof(cb));
		int n,a,b;
		char sex;
		scanf("%d",&n);
		for(int j=1 ; j<=n ; j++){
			getchar();
			scanf("%c %d %d",&sex,&a,&b);
			if(sex == 'M'){
				for(int q=a ; q<=b ; q++){
					cb[0][q]++;
				}
			}else{
				for(int q=a ; q<=b ; q++){
					cb[1][q]++;
				}
			}
			
		}
		int max = 0;
		for(int j=1 ; j<=366 ; j++){
			if(cb[0][j]&&cb[1][j]){
				if(max<min(cb[0][j],cb[1][j])){
					max = min(cb[0][j],cb[1][j]);
				}
			}
		}
		printf("Case #%d:\n%d\n",i,max*2);
	}
}

茅亭里看雨 切西瓜

签到题

简单判断即可

#include<stdio.h>
int main(){
	int t;
	scanf("%d",&t);
	for(int i=1 ; i<=t ; i++){
		int w;
		scanf("%d",&w);
		printf("Case #%d:\n",i);
		if(w==2)
			printf("NO\n");
		else{
			if(w%2==0)
				printf("YES\n");
			else
				printf("NO\n");
		}
	}
}

盛夏白瓷梅子汤

7和9,我们在1000内可以组成

9,7,97,99,77,79,999,997,977,777,779,799,979,797

数量不多,我们可以直接写出然后遍历即可

#include<stdio.h>
int main()
{
	int i,n,flag=0;
	int a[20]={9,7,97,99,77,79,999,997,977,777,779,799,979,797};
	int t;
	scanf("%d",&t);
	for(int q=1 ; q<=t;  q++){
		scanf("%d",&n);
		flag = 0;
		for(i=0;i<14;i++)
		{
			if(n%a[i]==0)
			   flag=1;
		}
		printf("Case #%d:\n",q);
		if(flag==1)
		   printf("Shmily\n");
		else
		   printf("NoShmily\n");
	}
}

秉烛夜游 一醉方休

先看m%n是否除的尽

可以的话,然后算出m是n的多少倍,然后倍数来不停除3,除2,每出一次步数ans++,如果最后的结构不等于1,就不满足,例如 n=1,m=5,满足的话,除完一定等于1.

#include<stdio.h>

int main() {
    int t, n, m, cnt;
    int step = 0;
    scanf("%d", &t);
    for (int i = 1; i <= t; ++i) {
        step = 0;
        scanf("%d%d", &n, &m);
        printf("Case #%d:\n", i);
        if (m % n != 0) {
            printf("-1\n");
            cnt = 1;
        } else {
            m = m / n;
            cnt = 0;
            while (m != 1) {
                if (m % 2 == 0) {
                    step++;
                    m = m / 2;
                    continue;
                }
                if (m % 3 == 0) {
                    step++;
                    m = m / 3;
                    continue;
                }
                printf("-1\n");
                cnt = 1;
                break;
            }
        }
        if (cnt == 0)
            printf("%d\n", step);
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值