#补题1 首届哈尔滨理工大学(荣成)"歌尔创客杯"新生赛

这是一篇起草于19年12月24日的文章,但因为种种原因没有及时完成,所以下面说了第一次写…

第一次写,可能会有很多不足的地方,还希望多多改正错误,一步一步认真地走下去吧。
本文题目顺序与原比赛顺序不同,纯因个人解题早晚…

一、
链接:https://ac.nowcoder.com/acm/contest/3474/F
来源:牛客网

有一群耗纸,它们喜欢在ACM协会的集训楼的电梯里反复玩弄电梯(假定有这栋楼。。。),这些耗纸定义了一种规则,当他们从一楼涌进电梯之后,每只耗纸都会在电梯上啪啪啪,到处乱拍,第i只耗纸,把楼层是i的倍数全都按了一遍,也就是说第13只耗纸会把第13,26,39等楼全部按一遍,假设这个电梯的质量比较好,开始的时候全是灭的,而且电梯上的按键,每按一次会亮,再按一次会灭掉,再按一次会亮,周而复始。如果知道会长的女神正在n楼自习,会长身边有n只耗纸,他想要尽快的见到他的女神,但是会长不知道这样n只手贱的耗子在一起坐电梯能不能顺利到达n层,因此他想请hlgrc的acmer们帮他算算,他该不该和这些手贱的耗纸一起坐电梯。

输入描述:
多组测试,每组输入一个数字n(0<n<10^15);

当n=0时,程序退出,该组数据不运行;
输出描述:
如果会长该和这些手贱的耗纸一起坐电梯,输出“Goddess,I’m coming~~~”

否则输出“Farewell~”
示例1
输入
11
13
1
0
输出
Farewell~
Farewell~
Goddess,I’m coming~~~

说明
第一组样例,一共有11只耗子,第一只耗纸会把所有的楼层全部按一遍,第二只会把2,4,6,8,10按一遍,…直到第11只耗纸把11层按一遍,那么电梯最后会去的楼层有只有4楼,会长懒得爬楼梯,因此见不到自己的女神,而女神也因为等不到会长,抑郁而终。

思路:按了奇数次是亮的,按了偶数次是暗的,一开始的想法是,遍历找到n的因数,于是弄一个flag记录第n层按钮的亮暗情况。
我一开始写的代码是下面这个,但是…题目给的数据最大是10^15,显然会超时orz…

#include<stdio.h>
typedef long long ll;
ll n;
int main()
{
	int flag=0;
	while(scanf("%lld",&n)!=EOF){
	if(n==0) break;
	for(int i=1;i<=n;i++)
	{
		if(n%i==0) flag=1-flag;
	}
	if(flag==1)
	{
		printf("Goddess,I'm coming~~~\n");
	}
	else{
		printf("Farewell~\n");
	}
	}
	return 0;
 } 

其实,在sqrt(n)的前与后会刚好有两个数相乘是n,相当于按了第n层的按钮两次(暗了)
那么,是否存在一种情况这个按钮只会被按一次呢?
当一个数b,满足b*b=n时就行了,它只有一个数,所以只会按一次。(注:数据可能很大,b用long long定义
(剽了别人的代码)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
    ll n;
    while(cin>>n&&n){
        ll b=sqrt(n);
        if(b*b==n)
            cout<<"Goddess,I'm coming~~~"<<endl;
        else
            cout<<"Farewell~"<<endl;
    }
 
    return 0;
}

二、
链接:https://ac.nowcoder.com/acm/contest/3474/D
来源:牛客网

题目描述
我们每次使用电脑都是会操成一些电脑磨损的,根据ACM协会研究表明,计算机开机后并连续工作4个小时以内会磨损10个单位的磨损(提示:0-4);接下来的4个小时(提示:4-8),每小时会造成2个单位的磨损;之后每小时会造成2.4个单位的磨损(提示:8-正无穷)。电脑最后使用时间既使不到1小时,也当作1小时计算磨损程度。(可以通过重启来结束连续工作,连续工作时间将清零)
一个参赛者可以根据计算机使用总时长合理安排时间,来让电脑的磨损程度降到最低。
例如,整个使用时间为16小时,使用者应该将使用时间分成长度相同的两部分,即在连续使用八小时时进行重启,每部分磨损18个单位,总共磨损了36个单位。如果电脑一直使用,则耗费37.2个单位。。
现在给你整个电脑的使用时间,请你计算使用电脑的最小磨损程度。
输入描述:
输入包含多组测试数据。每组输入一个正整数n(n<10000000),表示整个电脑使用时间。

当n=0时,输入结束。
输出描述:
对于每组输入,输出最小花费。如果需要的话,保留一位小数。
示例1
输入
3
9
16
0
输出
10
20.4
36
这种题基本上你把关系理清就能ac了…
我自己一直都是打代码的时候思路不清,希望自己这方面要改改了,今天晚上补了一下,其实也容易理解。比较每一个时间段的磨损,分析一下就行

直接上代码

#include<stdio.h>
int main()
{
	int n;
	double ans;
	int m;
	while(scanf("%d",&n)!=EOF&&(n!=0))
	{

		if(n<=4)
		{
			m=10;
			printf("%d\n",m);
		}
		else if(n<=8)
		{
			m=10+(n-4)*2;
			printf("%d\n",m);
		}
		else
		{
			if(n%8==0)
			{
				m=n/8*18;
				printf("%d\n",m);
			}
			else if((n%8)<5)
			{
				ans=n/8*18+n%8*2.4;
				printf("%.1lf\n",ans);
			}
			else if((n%8)>=5)
			{
				m=n/8*18+10+(n%8-4)*2;
				printf("%d\n",m);
			}
		}
	}
	return 0;
}

三、
链接:https://ac.nowcoder.com/acm/contest/3474/I
来源:牛客网

题目描述
ACM协会的会员越来越多了,训练量也越来也大,为使会员们在高强度的训练下得到放松,会员之间更加亲近,协会想为会员们准备一个晚会,晚会节目由会员们表演。
消息一出,报名要表演节目的会员很多,多达N个,尤其是才华横溢的史老师,点名要上台唱毛不易的《消愁》,但是由于场地和时间有限,只能从这N个人中选M个,请你帮会长算一算,一共有多少种选择方法?
输入描述:
数据的第一行是一个正整数T,接下来有T组数据,每组数据占一行。

每组数据包含两个整数N(来报名的人数,1<=N<=30),M(节目需要的人数0<=M<=30)。
输出描述:
每组数据输出一个整数,每个输出占一行。
示例1
输入
5
3 2
5 3
4 4
3 6
8 0
输出
3
10
1
0
1

这个题乍一看很简单…其实真的很简单,但是要注意数据范围,不能算30!,long long也会爆掉
因为碰巧上周学校C语言机考模拟的时候遇到这样的题
然后有一个公式C(n,r)=n!/(r!*(n-r)!)特别好用…这一上来就直接想着阶乘了…orz

上一份ac的代码

#include<stdio.h>
#include<math.h>
int main()
{
	int t;
	scanf("%d",&t);
	int n,m,i,j;
	long long c;
	for(j=0; j<t; j++)
	{
		scanf("%d %d",&n,&m);
		for(i=1,c=1; i<=m; i++)
		{
			c=c*(n+1-i)/i; //这里要先乘再除,保证它是整除
		}
		printf("%d\n",c);
	}
	return 0;
}

这题也有递归的写法,找到递归出口,C(1,1)=1;
利用高中学过的组合数之间的运算关系即可
以下来自某dl:

#include<bits/stdc++.h>
using namespace std;
long long a[50][50];  //全局变量,初值为0
long long c(int m,int n)
{
	for(int i=0; i<=50; i++)
	{
		a[i][0]=1;
		a[i][i]=1;
	}
	if(n==1&&m==1)
		return 1;
	else
		return a[m][n]!=0?a[m][n]:a[m][n]=c(m-1,n-1)+c(m-1,n);    //条件运算符

}
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		int m,n;
		cin>>m>>n;
		if(n>m)
			printf("0\n");
		else
			printf("%lld\n",c(m,n));
	}
	return 0;
}

四、
链接:https://ac.nowcoder.com/acm/contest/3474/C
来源:牛客网

题目描述
在这里插入图片描述
如图所示为一个由n个圆圈构成的圆环。将自然数1,2,…,n放入圆圈内,并且要求任意两个相邻的圆圈内的数字之和为素数。请问给你圆圈数,你能给出放置自然数的所有正确方案吗?
注意:圆圈中的数字一定是从1开始的,并且连续不重复。

输入描述:

输入包含多组测试数据。每组输入占一行,为整数n(0<n<20),表示圆圈数。

输出描述:

对于每组输入,输出所有正确的方案,按字典序从小到大排序。每组输出后输出一个空行。具体输出格式见输出样例。

示例1

输入
6
8
输出
Case 1:
1 4 3 2 5 6
1 6 5 2 3 4

Case 2:
1 2 3 8 5 6 7 4
1 2 5 8 3 4 7 6
1 4 7 6 5 8 3 2
1 6 7 4 3 8 5 2

备注:
注意:只能按照顺时针方向放置数字。

//dfs基础题

#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
int a[30];
bool isprime(int n)
{
	for(int i=2; i*i<=n; i++)
	{
		if(n%i==0)
		{
			return false;
		}
	}
	return true;
}
int n;
int vis[30];
int x=1;
void dfs(int x)     //x指这次找的数是第几个数
{
	if(x==n+1&&isprime(a[x-1]+1))
	{
		for(int i=1; i<n; i++)
		{
			printf("%d ",a[i]);
		}
		printf("%d\n",a[n]);
	}
	for(int i=2; i<=n; i++)
	{
		if(isprime(i+a[x-1])&&!vis[i])
		{
			vis[i]=1;   //保存结果
			a[x]=i;
		/*找到第x个数符合条件的就找第(x+1)个数*/
			dfs(x+1);
			vis[i]=0;   //回溯,状态清除
		}
	}
}

int main()
{
	while(scanf("%d",&n)!=EOF)
	{
		memset(vis,0,sizeof(vis));
		a[1]=1;
		vis[1]=1;
		printf("Case %d:\n",x++);
		dfs(2);
		printf("\n");
	}
	return 0;
}

五、
链接:https://ac.nowcoder.com/acm/contest/3474/J
来源:牛客网

题目描述
圣诞节将至,会长为了得到圣诞礼物参加了迷宫抢旗活动。这个迷宫有N个红旗,这N个红旗之间只有N-1条路可以互通,他要都拿到且不走重复路才可以得到奖品。活动人员发放地图给他,现在他在第S个红旗处,他想要拿到第T个红旗,必须先经过的前一个红旗处是第几个?

输入描述:
第一行输入一个整数M表示测试数据共有M(1<=M<=5)组

每组测试数据的第一行输入一个正整数N(1<=N<=100000)和一个正整数S(1<=S<=100000),N表示红旗的总个数,S表示会长所在红旗处

随后的N-1行,每行有两个正整数a,b(1<=a,b<=N),表示第a个红旗和第b个红旗之间有一条路连通。

输出描述:

每组测试数据输N个正整数,其中,第i个数表示从S走到i个红旗,必须要经过的上一个红旗的编号。(其中i=S时,请输出-1)
示例1

输入

1
10 1
1 9
1 8
8 10
10 3
8 6
1 2
10 4
9 5
3 7

输出

-1 1 10 10 9 8 3 1 1 8

类型:dfs+stl
我还是个搜索小垃圾,一直要看别人的代码才会写orz…
看了别人的代码,自己码起来,上代码

#include<bits/stdc++.h>
using namespace std;
int a[100005];  //a[i]表示到i位置时必须经过的上一个旗子的编号
/*利用vector第一维定长为MAX,第二维任意的特性。避免内存溢出*/
vector<int> v[100005];
int t,n,s,x,y;
void dfs(int pre,int now)   //现在操作的位置为now,它经过的上一个旗子的编号为pre
{
	if(a[now])    //搜索就是为了记录上一个旗子的编号,如果已经记录了,就是退出搜索
	{
		return;
	}
	a[now]=pre;  //记录上它经过上一个旗子的编号
	for(int i=0; i<v[now].size(); i++)  //v[now].size()指现在和now相连的有几个,遍历一下
	{
	/*v[now][i]是下一个*/
		if(v[now][i]==pre) //下一个可不能找上一个绕回去了,如果是上一个就不搜索
			continue;
		dfs(now,v[now][i]); //反之,搜索
	}
}
int main()
{
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d %d",&n,&s);
		memset(a,0,sizeof(a));
		for(int i=1;i<=n-1;i++)
		{
			scanf("%d %d",&x,&y);
			v[x].push_back(y); //把数放入数组
			v[y].push_back(x);
		}
		dfs(-1,s);
		for(int i=1; i<=n; i++)
		{
			printf("%d ",a[i]);
		}
		printf("\n");
	}
	return 0;
}

至此,首届哈尔滨理工大学(荣成)"歌尔创客杯"新生赛的补题就结束了。希望下次我能按时补题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值