大年初二红包赛题解

 

首先要超级感谢“灯神”——丁凯朔同学的耐心解答,蟹蟹这位兄dei救我于水火,因此这些感谢的话必须放在C位——最显眼的位置上。你可以不看题解,但必须得瞻仰一下他的大名,没错就是这样哈哈~

多余的空话不多说,也不会说,但这份感谢是放在心里啦,好兄弟谢谢你!(顺便说一句,zg是我“儿子”,这辈分你懂得~)

 

1.无聊的hbz (细心审题)

大年初二,走亲戚回来,hbz过于无聊,在网上打起了电风扇的主意,
电风扇是由开关控制的,(按一下就吹风,再按一下就关了),
hbz把 2000 个电风扇 3 的倍数按了一次,5 的倍数按了一次,
7的倍数按了一次,11的倍数按了一次(电风扇的编号从 1-1000,电风扇的初始状态都是关的)。
以上操作完之后,hbz在想还剩下几个电风扇还在吹风

答案是一个整数,请通过浏览器直接提交该数字。

#include<iostream>
#include<cmath>
#include<cstring>
#include<string>
using namespace std;
int a[2005];
int main(){ 
	memset(a,-1,sizeof a);                 //用-1表示off,用1表示on
	for(int i=1;i<=2000;i++){
		if(i%3==0) a[i]=-a[i];
		if(i%5==0) a[i]=-a[i];
		if(i%7==0) a[i]=-a[i];
		if(i%11==0) a[i]=-a[i];
	}
	int ans=0;
	for(int i=1;i<=2000;i++){
		if(a[i]==1) ans++;
	}
	cout<<ans<<endl;
	return 0;
}

 

 

2.【羊羊过桥】(太低估小羊的智商了——贪心)

青青草原上的羊羊们被灰太狼追到了的河边,河边有一座小桥,4只小羊都在桥的同一边。
这时是晚上,他们只有一个手电筒,每次最多只能让两只羊同时过桥。不管是谁过桥,
不管是一只羊还是两只羊,必须要带着手电筒。手电筒必须要传来传去,不能扔过去。
每只羊过桥的速度不同,两只羊的速度必须以较慢的那只羊的速度过桥。如果他们自己过桥,
他们所需要的时间如下:
喜羊羊:过桥需要1分钟;
美羊羊:过桥需要2分钟;
懒羊羊:过桥需要5分钟;
慢羊羊:过桥需要8分钟.
求所有羊羊通过桥所需要的最短时间?

答案是一个整数,请通过浏览器直接提交该数字。

即先排序,后比较以下哪种解法更省时间

  • a[0]+a[1]过去,a[0]回来,a[0]+a[2]过去,a[0]回来,a[0]+a[3]过去,over(a[0]为传手电筒使者)
  • a[0]+a[1]过去,a[0]回来,a[2]+a[3]过去,a[1]回来,a[0]+a[1]过去,over

 

 3.拼火柴(特况判断不能少,致命的小错误)

小明帮妹妹辅导寒假作业,其中一道题是利用火柴棒拼等式,题目给你20根火柴棍,问可以拼出多少个形如 "A+B=C" 的等式?

注意:
数字0-9分别需要的火柴棒的数目为: 6,2,5,5,4,5,6,3,7,6 
等式中的 A、B、C 是用火柴棍拼出的整数
若A、B、C 不为0,则最高位不能为0
加号与等号各自需要两根火柴棍
如果 A!=B,则 A+B=C与 B+A=C 视为不同的等式(A,B,C>=0)
n 根火柴棍必须全部用上

答案是一个整数,请通过浏览器直接提交该数字。

#include<iostream>
using namespace std;
int a[20]= {6,2,5,5,4,5,6,3,7,6};
int f(int x) {
	int tmp=0;
	if(x==0) tmp+=a[0];   //一定要注意特况判断!  
	while(x) {
		tmp+=a[x%10];
		x/=10;
	}
	return tmp;
}
int main() {
	int ans=0;
	for(int i=0; i<= 1000; i++) {
		for(int j=i; j<=1000; j++) {
			if(f(i)+f(j)+f(i+j)==16){
				if(i==j) ans++;
				else ans+=2;
				cout<<i<<' '<<j<<' '<<i+j<<endl;
			}
		}
	}
	cout<<ans;
	return 0;
}

 

4.是男人就挑战一百层(出题不严谨,但重在领会精神)


如果一个人从最高N层楼跳下去毫发无损,就称他(她)的战力为N,一个人的最高战力为100(从100层以上的楼层跳下均记为100)。
现在要测试每个人的战力。当然不是真的去跳楼,有一个模拟机器,可以模拟跳楼后的数据,但是每次只能选定一层楼模拟,然后机器给出对应的数据,那么要想测出一个人的战力,在最坏情况下,需要模拟几次?
假设甲由3楼跳下,毫发无损,6楼跳下有损伤,5楼跳下毫发无损,那么他的战力为5,测试次数为3次。
请求出在最坏情况下测出一个人的战力的最少模拟次数。

(原题目为有且只有两个鸡蛋,摔坏就没了)

原文:https://blog.csdn.net/Sirius_han/article/details/81152572 (个人在代码处略加注释,此外均为引用原文,在此感谢原博主分享心得)

现有两个硬度相同的鸡蛋,以及一栋100层的楼,如果鸡蛋在第n层楼摔下去不会碎,在n-1层楼摔下去会碎,那么鸡蛋的硬度是n,如果要测出鸡蛋的硬度n,在最坏情况下最少要测试几次?每测试一次就把一个鸡蛋从x层楼扔下去;只有两个鸡蛋可用,鸡蛋摔碎了就不能用了;

题目分析:

1:二分????

刚开始看到这个题脑子里最先蹦出来的就是二分;每次取一半,log(n)的算法,然后稍微深入分析一下就悲剧了;

按照二分思路,第一个鸡蛋在50层扔下,没有碎;75层,还没碎;88层,仍然坚强不碎;94层,还是一如既往的坚固;97层,还不碎????!!!;99层,,,,,,100层;7次就测出来了;你这么能咋不直接从100层扔鸡蛋?直接不碎,1次就测出来了。。。

注意题目要求最坏情况;什么是最坏情况?第一个鸡蛋50层就碎了,还剩一个鸡蛋,此时你只能乖乖的从第1层开始测试,不然的话,50层之后直接到25层,第二个鸡蛋也碎了就测不出鸡蛋的强度了;

所以二分在最坏情况下需要测50次:第一个鸡蛋在50层碎了,第二个鸡蛋从第一层测试到49层:1+49=50;

2:分段????

第一次测x层,没破测2*x层,依次递推,如果在i*x层破了,就从(i-1)*x+1层开始一直测到i*x层,

经过计算发现最优的x是8, 9, 10, 11, 12, 13,此时需要测k=19次(100/x+(x-1));

这个好像比较靠谱,19次就能测出来,比二分靠谱多了;难道就没有更好的方法了吗????

3:递推!!!

如果第一次扔鸡蛋,鸡蛋就碎了,那么第二个鸡蛋一定是从1层向上测试,此时如果第一次在第k层楼扔鸡蛋,鸡蛋卒,最坏情况下还需测k-1次,共计k次;现在我们假设最少就需要k次能测出鸡蛋硬度,第一次扔鸡蛋,鸡蛋卒的情况下最优解是k,若第一次鸡蛋生,第二次扔鸡蛋鸡蛋卒最优解也要是k的话,第二次一定在第k+k-1=2*k-1层楼扔鸡蛋,因为在第二次扔鸡蛋,鸡蛋卒后,就需要由第k+1层测试到第2*k-2层,测试了k-2次,共计1+1+k-2=k次;同理,如果第二次扔鸡蛋,鸡蛋未卒,第三次扔鸡蛋,鸡蛋卒,则第三次在第k+(k-1)+(k-2)层扔鸡蛋。。。依次递推当前k-1次鸡蛋都逃出生天,到第k次扔鸡蛋时已经该测试第k+(k-1)+(k-2)+(k-3)+···+1=(k+1)*k/2层楼了,也就是说,此楼最多(k+1)*k/2层才能通过最少k次测出鸡蛋硬度;

综上所述:当(k+1)*k/2>=n时,一定可以用k次测出在n层楼上鸡蛋的强度;

对于一个给定的n,取最小的k满足上式,k就是最优解;

当n=100时,k=14时最优;

4:动态规划!!!!

是不是很惊讶???!!!这样也能DP!!!

若n为楼层总数, 令f[n]为总共n层楼时的最优解;在第i层楼如果鸡蛋碎了, f[i]=i-1+1(从第一层开始测试);如果鸡蛋未碎, f[i]=f[n-i]+1(在剩下的n-i层楼测试最优解);所以:f[i]=max(i-1, f[n-i])+1;

f[n]=min(max(i-1, f[n-i])+1  |  i=1, 2, 3, 4, ···, n);

#include<iostream>
using namespace std;
int dp[105];	
int main(){
	dp[0]=0;    //!!!
	for(int i=1;i<=100;i++){
		dp[i]=i;
		for(int j=1;j<=i;j++)
			dp[i]=min(dp[i],max(j-1,dp[i-j])+1);
	}
	cout<<dp[100];
	return 0;
} 

 

 

将该题扩展一下, n层楼,m个鸡蛋如何推出最优解?

还是用DP做一下:f[n][m]表示n层楼m个鸡蛋时的最优解;

在第i层,有j个鸡蛋时,本次测试鸡蛋卒,f[i][j]=f[i-1][j-1]+1(用剩下的j-1个鸡蛋测试i-1层),鸡蛋生还f[i][j]=f[n-i][j]+1(继续用j个鸡蛋测试剩下的n-i层);f[i][j]=max(f[i-1][j-1], f[n-i][j])+1;

所以f[n][m]=min(max(f[i-1][j-1], f[n-i][j])+1  |   i=1, 2, 3, 4, ···, n)

#include<bits/stdc++.h>
using namespace std;
int main(){
	int f[105][105];                //f[n][m]表示n层楼m个鸡蛋时的最优解
	for(int i=0; i<=100; i++){
		f[i][1]=i;
	}
	for(int j=2; j<=100; j++)       //仅多一层j个鸡蛋的循环 
		for(int i=1; i<=100; i++){
			f[i][j]=i;
			for(int k=1; k<=i; k++){
			f[i][j]=min(f[i][j], max(f[k-1][j-1], f[i-k][j])+1);
			}
	}	
	cout << f[100][2] << endl;
	return 0;
}

 

 

 

5.【沙漠旅行】(审题有误+和的数据范围)

探险家要到沙漠旅行,途中有编号为1-n的n个城市,探险家从1号城市顺序向后走,一直走到n号城市,并从n号城市离开沙漠。
探险家的水壶中有一个初始水量,每个城市对应一个整数A[i],表示在这个城市可以获得的水量。如果A[i] > 0,探险家走到
这个城市能够获取A[i]的水,如果A[i] < 0,走到这个城市需要消耗相应的水,如果水壶的水量 < 0,就无法继续前进了。
问探险家初始最少需要携带多少的水,才能完成整个旅程。

输入
第1行:1个数n,表示城市的数量。(1 <= n <= 50000)
第2 - n + 1行:每行1个数A[i],表示城市中获得的水量(-1000000000 <= A[i] <= 1000000000)

输出
输出1个数,对应从1走到n初始最少需要携带多少的水。

输入样例
5
1
-2
-1
3
4

输出样例
2

 

#include<iostream>
#include<cmath>
#include<cstring>
#include<string>
#define Inf 1000000001
using namespace std;
typedef long long ll;  //单个数据不超范围,但是和呢?
int main() {
	int n,x;
        ll ans=0,sum=0;
	cin>>n;
	for(int i=1; i<=n; i++) {
		scanf("%d",&x);
		sum+=x;
		if(sum<0) {           //当时自己的错误:minn=min(minn,ans);
			ans+=abs(sum);
			sum=0;
		}
	}	
	cout<<ans<<endl;
	return 0;
}

 

6.标题:无人机航线规划(待更新……没错我就是懒,所以还没看;不用看了,这道题没有题解的哈哈)

某海岛遭遇飓风灾害,道路设施受损严重。救援部门为尽快探明主要交通干道的受损情况,在地图上划定了主要交通干道的侦察点,
(如图a所示),决定使用无人机对这些侦察点进行侦察。救援部门想知道,在只有一架无人机,且无人机有航程限制的情况下,考虑
无人机的返航,如何规划无人机的航线(如图b所示),才能对更多的侦察点进行侦察。

给出无人机的起点0的坐标(x0,y0),侦察点的数量n,  无人机的航程m,以及各侦察点i的坐标(xi,yi)。 

请输出覆盖最多侦察点的路径中航程最短的路径。若路径有多个,输出字典序最大的路径。
计算距离时请保留到小数点后两位。

【输入格式】
n m
x0 y0
x1 y1
x2 y2
. . .
xn yn 

对于40%的数据,0<n<5;  
对于70%的数据,0<n<7;  
对于100%的数据, 0<n<10; 10<m<100; -10 <= xi, yi <= 10 ; 


【输出格式】
输出无人机的侦察航线

【输入样例1】
5 35
4 1
2 7
7 1
0 8
-3 -3
3 6
【输出样例1】
0->4->3->1->5->2->0

【输入样例2】
10 45
0 0
9 -6
-2 -5
9 1
9 9
6 0
-8 -7
4 -2
10 7
-6 2
-3 6
【输出样例2】
0->9->10->4->8->3->5->7->0


资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗  < 2000ms

 

 

7.龙宫盗宝(中国最“贪心”小偷,没有之一)

老龙王酷爱收藏宝贝,他搜罗了很多宝贝藏在他的龙宫之中。某日一小偷潜入龙宫之中企图盗窃龙宫宝物。假设宝物是被一字排列的,每个宝物都装在一个盒子里,老龙王在某些盒子里设计了一些陷阱。小偷如果拿到装有宝物的盒子,则会获得一定的收益,如果盒子里有陷阱则会有一定的损失。小偷为了尽快的拿走宝物而不被发现,决定从某个盒子开始,连续的拿走若干的盒子。问小偷从哪个盒子开始拿并且拿多少个盒子,才能使得到的收益最高。


输入描述


题目包含多组输入
n表示有n个盒子(n<=1000000),随后n个数表示每个盒子能带来的收益val,(-100<=val<=100)。


输出描述


输出两个值小偷拿的第一个盒子的位置i(从1开始数),拿走盒子的个数k。中间用空格隔开。如果有多种结果,要求在i尽量小的前提下k尽量大(因为小偷很贪心,他总想多拿一点,当然知晓老龙王阴险的他也可以一个都不拿并输出"龙宫如此之穷")。


### 输入示例
5 -1 2 3 -2 4

### 输出示例
2 4

提示
选择 2 3 -2 4

#include<iostream>
#define Inf 1000000001
using namespace std;
int main() {
	int n,x;
	while(cin>>n) {
		int sum=0,left=1,begin=1,end=1,maxn=-Inf;
		for(int i=1; i<=n; i++) {
			scanf("%d",&x);
			if(sum>=0)
				sum+=x;
			else{
				sum=x;
				left=i;
			}
			if(sum>=maxn){
				maxn=sum;
				begin=left;
				end=i;
			}
		}
		if(maxn<0) cout<<"龙宫如此之穷\n";
		else cout<<begin<<' '<<(end-begin+1)<<endl;
	}
	return 0;
}
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int N=1000005;
int a[N],dp[N];
int main(){
	int n;
	while(~scanf("%d",&n)){
		int flag=0,maxn=0,sum=0,start=0,end=0;
		memset(dp,0,sizeof dp);
		for(int i=1;i<=n;i++){
			scanf("%d",&a[i]);
			if(a[i]>=0) flag=1;    //标记是否有价值为正数or 0的宝藏可拿 
		}
		if(flag==0){
			printf("龙宫如此之穷\n");
			continue;              //直接退出提高效率 
		}
		for(int i=1;i<=n;i++){
			dp[i]=max(dp[i],dp[i-1]+a[i]);
			if(dp[i]>=maxn){
				maxn=dp[i];
				end=i;
			}
		}
		for(int i=end;i>=1;i--){
			sum+=a[i];
			if(sum==maxn){
				start=i;
			      //break;   因为会有0啊 
			}
		}
		printf("%d %d\n",start,end-start+1);
	}
	return 0;
} 

 

 

 

8.yzm10铺地毯(样例画面太美我不敢看,题解代码好牛大佬风流,横批:顶礼膜拜!!!)

64MB/2000ms

继yzm10铺瓷砖后,我们又收到了一项重要的任务,Consumer要求yzm10在光滑的地面上再铺设一层地毯,并且邀请您进行设计。挑剔的Consumer选择了如(图片)所示图案。
谢尔宾斯基地毯:采用的是正方形进行分形构造,谢尔宾斯基地毯和它本身的一部分完全相似,因此具有自相似性。其三维结构便是著名的门格尔海绵。
yzm10给出了地毯的构造层数(n<6),现在请您进行设计。

输入:
一个正整数n

输出:
打印图案

样例说明:
为保证打印图案尽可能接近正方形,将"##"视作一个字符。行首行尾没有多余空格。

输入样例1:

1

输出样例1:

输入样例2:

2

输出样例2:

输入样例3

3

输出样例3:

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int mp[250][250];
void dfs(int x,int y,int len){             //中心点坐标及小一号的正方形边长 
	if(len==0) return;
	for(int i=x-len/2;i<=x+len/2;i++)      //将该小正方形所有空格标记 
		for(int j=y-len/2;j<=y+len/2;j++)
			mp[i][j]=true;
	dfs(x-len,y-len,len/3);dfs(x-len,y,len/3);dfs(x-len,y+len,len/3);  //第一行 
	dfs(x,y-len,len/3);dfs(x,y+len,len/3);                             //第二行 
	dfs(x+len,y-len,len/3);dfs(x+len,y,len/3);dfs(x+len,y+len,len/3);  //第三行 
	
}
int main(){
	int n;
	cin>>n;
	int len=pow(3,n);                     //大正方形边长 
	dfs(len/2+1,len/2+1,len/3);           //中心点坐标及小一号的正方形边长 
	for(int i=1;i<=len;i++){
		for(int j=1;j<=len;j++){
			if(mp[i][j]) printf("  ");
			else printf("##");
		}
		printf("\n");
	}
	return 0;
} 

 

 

9.最短时间

时间限制:500ms
内存限制:100M

梦工厂有 n 个分厂(从 1 开始编号),有m对分厂通过双向铁路相连。
为了保证每两个分厂之间的同学可以方便地进行交流,掌舵人张老师就在那些没有铁路连接的分厂之间建造了公路。
在两个直接通过公路或铁路相连的分厂之间移动,需要花费 1 小时。
现在菜鸡wxy和hbz都从1厂出发,wxy开火车,hbz开汽车,各自前往n厂。但是,他们中途不能同时停在同一个分厂
(但是可以同时停在n厂)。
现在请你来为wxy和hbz分别设计一条线路,使他们尽可能快地到达n厂(即要求他们中最后到达n厂的时间最短)。
所有的公路或铁路可以被多次使用,求最短时间。(火车和汽车可以同时到达n,也可以先后到达。)

输入:
首先有 2 个整数 n 和 m (2<=n<=500, 0<=m<=n*(n-1)/2 分别表示梦工厂分厂的数目和铁路的数目;
接下来的 m 对数字,每对由两个整数 u 和 v 构成,表示小镇 u 和小镇 v 之间有一条铁路。(u!=v  1<=u,v<=n)
输入保证无重边

输出
输出一个整数,表示答案,如果没有合法的路线规划,输出-1

输入样例:
4 3 
1 2
2 3
3 4

输出样例:
3

根据题意,只用求1与n之间 没有路的那种交通方式 从1~n的time(Dijkstra算法)。

至于题目要求两人不能同时停在2~n-1之间的任意一个站点什么的都是唬人的……虽然现在说来简单,可当时我就是没反应过来,怪我太年轻~

#include<iostream>
#include<cstring>
#include<cmath>
#define Inf 0x3f3f3f3f
using namespace std;
int n,m;
int dis[505],vis[505];
int mp[505][505];
void dijkstra(int val){  
	for(int i=1;i<=n;i++){  //一定要转化,确认是走公路的还是走铁路的人慢 
		for(int j=1;j<=n;j++){
			if(i==j) mp[i][j]=0;
			else if(mp[i][j]==val) mp[i][j]=1;
			else mp[i][j]=Inf;
		}
	}
	dis[1]=0;      //别忘了!!! 
	for(int i=1;i<n;i++){
		int minn=Inf,index=-1;
		for(int j=1;j<=n;j++){
			if(!vis[j]&&dis[j]<minn){
				minn=dis[j];
				index=j;
			}
		}
		if(index==-1) break;
		vis[index]=1;
		for(int j=1;j<=n;j++)
			if(mp[index][j]!=Inf&&!vis[j]&&dis[j]>dis[index]+mp[index][j]) //第一个判断必不可少!主要适用于用0代替Inf时 
				dis[j]=dis[index]+mp[index][j];		
	}
}
int main(){
	int u,v;
	scanf("%d%d",&n,&m);
	memset(vis,0,sizeof vis);
	memset(dis,Inf,sizeof dis);
	for(int i=1;i<=m;i++){
		scanf("%d%d",&u,&v);
		mp[u][v]=mp[v][u]=1;
	}
	dijkstra(!mp[1][n]);    //很巧妙的传参技巧! 
	printf("%d\n",dis[n]==Inf?-1:dis[n]);
	return 0;
} 

 

 

 

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值