大年初二紅包賽題解

 

首先要超級感謝“燈神”——丁凱朔同學的耐心解答,蟹蟹這位兄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;
} 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章