这是一篇起草于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;
}
至此,首届哈尔滨理工大学(荣成)"歌尔创客杯"新生赛的补题就结束了。希望下次我能按时补题。