洛谷刷題記錄(一)【入門】


P2036 [COCI2008-2009#2] PERKET

題目描述

Perket 是一種流行的美食。為了做好 Perket,廚師們必須小心選擇配料,以便達到更好的口感。你有N種可支配的配料。對於每一種配料,我們知道它們各自的酸度 S 和甜度 B。當我們添加配料時,總的酸度為每一種配料的酸度總乘積;總的甜度為每一種配料的甜度的總和。

眾所周知,美食應該口感適中;所以我們希望選取配料,以使得酸度和甜度的絕對差最小。

另外,我們必須添加至少一種配料,因為沒有美食是以白水為主要配料的。

輸入格式

第一行包括整數 N,表示可支配的配料數。
接下來 N 行,每一行為用空格隔開的兩個整數,表示每一種配料的酸度和甜度。
輸入數據保證,如果我們添加所有配料,總的酸度和甜度都不會超過 \(10^9\)

輸出格式

輸出酸度和甜度的最小的絕對差。

輸入輸出樣例

輸入 #1

1
3 10

輸出 #1

7

輸入 #2

4
1 7
2 6
3 8
4 9

輸出 #2

1

說明/提示

\(1 \le N \le 10.\)

我的思路

本題搜索最小值,可用深度優先搜索(DFS)解題。

首先選擇一個入口,即第一組選擇的調料(這個入口從第一組到最后一組遍歷進入dfs模塊,記住這個入口點,如果是第一次記得初始化最小值);接着再編寫dfs函數,分兩種情況:一種普通情況繼續搜索,即在之前的選擇上繼續選擇,並且每一次選擇后都要計算總酸度與總甜度之差,如果小於我們記錄的最小值則更新,完了返回來的時候再將酸度和甜度修改回去,繼續遍歷。二是選擇到最后一組調料了,這時候搜索到頭了,直接RETURN結束這次搜索。

注意我們的搜索是從前往后按順序來的,這樣可以避免重復。

AC代碼

#include<stdio.h>
int s[10], b[10];
int n;
long ans;  //最后結果 

void dfs(long mul, long sum, int start){
	if(start==n-1){  //每次到最后一組調料就結束 
		return;
	}
	else{
		for(int i=start+1; i<n; i++){  //從前往后選調料,避免重復 
			mul *= s[i];
			sum += b[i];
			long tmp = mul-sum>0?mul-sum:sum-mul;
			if(tmp < ans) ans = tmp;
			dfs(mul, sum, i);  //遞歸進行疊加選擇 
			mul /= s[i];       //恢復當前總酸度和總甜度,以便進行下一次選擇 
			sum -= b[i];
		}
	}
}

int main(){
	scanf("%d", &n);
	for(int i=0; i<n; i++){
		scanf("%d%d", &s[i], &b[i]);
	}
	for(int i=0; i<n; i++){  //選擇開始第一種配料開始遍歷搜索 
		long mul = s[i];
		long sum = b[i];
		long tmp = mul-sum>0?mul-sum:sum-mul;
		if(i==0 || tmp<ans) ans = tmp;
		dfs(mul, sum, i);
	}
	printf("%ld", ans);
	
	return 0;
}

---2020/7/27---


P2676 [USACO07DEC]Bookshelf B

題目描述

Farmer John最近為奶牛們的圖書館添置了一個巨大的書架,盡管它是如此的大,但它還是幾乎瞬間就被各種各樣的書塞滿了。現在,只有書架的頂上還留有一點空間。

所有N(1 <= N <= 20,000)頭奶牛都有一個確定的身高H_i(1 <= H_i <= 10,000)。設所有奶牛身高的和為S。書架的高度為B,並且保證 1 <= B <= S < 2,000,000,007。

為了夠到比最高的那頭奶牛還要高的書架頂,奶牛們不得不像演雜技一般,一頭站在另一頭的背上,疊成一座“奶牛塔”。當然,這個塔的高度,就是塔中所有奶牛的身高之和。為了往書架頂上放東西,所有奶牛的身高和必須不小於書架的高度。

顯然,塔中的奶牛數目越多,整座塔就越不穩定,於是奶牛們希望在能夠到書架頂的前提下,讓塔中奶牛的數目盡量少。 現在,奶牛們找到了你,希望你幫她們計算這個最小的數目。

輸入格式

第1行: 2個用空格隔開的整數:N 和 B * 第2..N+1行: 第i+1行是1個整數:H_i

輸出格式

第1行: 輸出1個整數,即最少要多少頭奶牛疊成塔,才能夠到書架頂部

輸入輸出樣例

輸入 #1

6 40
6
18
11
13
19
11

輸出 #1

3

說明/提示

輸入說明:

一共有6頭奶牛,書架的高度為40,奶牛們的身高在6..19之間。

輸出說明:

一種只用3頭奶牛就達到高度40的方法:18+11+13。當然還有其他方法,在此不一一列出了。

我的思路

顯然我們最容易想到的思路就是將奶牛的身高從大到小排序,循環減去奶牛身高並計數,得出最終答案。

考慮到奶牛數量,我們可以選擇排序較快的算法,這時我們想到C++的STL里的sort函數,當然它並不一定是快速排序,它會根據實際數量來選擇更優的排序算法,這也恰好滿足了我們的需要。

AC代碼

#include<cstdio>
#include<algorithm>
using namespace std;
int n,h[20005], ans;
long s, b;

bool cmp(int a, int b){
	return a>b;
} 

int main(){
	scanf("%d%d", &n, &b);
	for(int i=0; i<n; i++){
		scanf("%d", &h[i]);
	}
	sort(h, h+n, cmp);
	for(int i=0; b>0; i++){
		b = b - h[i];
		ans++;
	}
	printf("%d", ans);
	
	return 0;
}

---2020/7/28---


P1116 車廂重組

題目描述

在一個舊式的火車站旁邊有一座橋,其橋面可以繞河中心的橋墩水平旋轉。一個車站的職工發現橋的長度最多能容納兩節車廂,如果將橋旋轉180180度,則可以把相鄰兩節車廂的位置交換,用這種方法可以重新排列車廂的順序。於是他就負責用這座橋將進站的車廂按車廂號從小到大排列。他退休后,火車站決定將這一工作自動化,其中一項重要的工作是編一個程序,輸入初始的車廂順序,計算最少用多少步就能將車廂排序。

輸入格式

共兩行。

第一行是車廂總數N( \(\le\) 10000)。

第二行是N個不同的數表示初始的車廂順序。

輸出格式

一個整數,最少的旋轉次數。

輸入輸出樣例

輸入 #1

4
4 3 2 1

輸出 #1

6

我的思路

相鄰兩數交換位置,使得最終結果從小到大排序,仔細一想,這不就是冒泡排序么?!

AC代碼

#include<stdio.h>
int n, len[10005], ans;
int main(){
	scanf("%d", &n);
	for(int i=0; i<n; i++){
		scanf("%d", &len[i]);
	}
	for(int i=0; i<n-1; i++){  // 每次循環都有一個最大值“冒泡”到最后,n-1次后剩下1個最小的不必排 
		for(int j=0; j<n-i-1; j++){  // 每次冒泡只需到未排序區,“已冒出的泡”無需再排 
			if(len[j] > len[j+1]){  // 相鄰比較,大者后移 
				int tmp = len[j];
				len[j] = len[j+1];
				len[j+1] = tmp;
				ans++;
			}
		}
	}
	printf("%d", ans);
	
	return 0;
}

---2020/7/29---


P2956 [USACO09OCT]The Robot Plow G

題目描述

Farmer John has purchased a new robotic plow in order to relieve him from the drudgery of plowing field after field after field. It achieves this goal but at a slight disadvantage: the robotic plow can only plow in a perfect rectangle with sides of integer length.

Because FJ's field has trees and other obstacles, FJ sets up the plow to plow many different rectangles, which might end up overlapping. He's curious as to just how many squares in his field are actually plowed after he programs the plow with various plow instructions, each of which describes a rectangle by giving its lower left and upper right x,y coordinates.

As usual, the field is partitioned into squares whose sides are parallel to the x and y axes. The field is X squares wide and Y squares high (1 <= X <= 240; 1 <= Y <= 240). Each of the I (1 <= I <= 200) plow instructions comprises four integers: Xll, Yll, Xur, and Yur (1 <= Xll <= Xur; Xll <= Xur <= X; 1 <= Yll <= Yur; Yll <= Yur <= Y) which are the lower left and upper right coordinates of the rectangle to be plowed. The plow will plow all the field's squares in the range (Xll..Xur, Yll..Yur) which might be one more row and column than would initially be assumed (depending on how you go about your assumptions, of course).

Consider a field that is 6 squares wide and 4 squares high. As FJ issues a pair of plowing instructions (shown), the field gets plowed as shown by '*' and '#' (normally plowed field all looks the same, but '#' shows which were most recently plowed):

......
......
......
......

(1,1)(2,4)

**....
**....
**....
**....

(1,3)(5,4)

#####.
#####.
**....
**....

A total of 14 squares are plowed.

POINTS: 25

輸入格式

Line 1: Three space-separated integers: X, Y, and I

輸出格式

Lines 2..I+1: Line i+1 contains plowing instruction i which is described by four integers: Xll, Yll, Xur, and Yur

輸入輸出樣例

輸入 #1

6 4 2
1 1 2 4
1 3 5 4

輸出 #1

14

說明/提示

As in the task's example.

我的思路

本題難點在於如何知道哪些格子重復了,一開始我思考怎么避免這一次的區域和上一次部分重合,但是這樣也不能避免和所有之前所有的區域都避免重合,不說存儲,光是判斷就要浪費很多時間。

后來我一拍大腿,這不就是統計有多少地從沒耕到耕了的狀態嗎?!這樣用一個bool數組記錄就可,每次耕一塊新地都計數,這個題目立即就簡單的不得了!

AC代碼

#include<cstdio>
int x, y, n;
long ans, xll, yll, xur, yur;
bool mp[245][245]; 
int main(){
	scanf("%d%d%d", &x, &y, &n);
	for(int i=0; i<n; i++){
		scanf("%ld%ld%ld%ld", &xll, &yll, &xur, &yur);
		for(int j=xll; j<=xur; j++){
			for(int k=yll; k<=yur; k++){
				if(!mp[j][k]){
					mp[j][k] = true;
					ans++;
				}
			}
		}
	}
	printf("%ld", ans);
	
	return 0;
}

---2020/7/30---


P1830 轟炸III

題目背景

一個大小為N*M的城市遭到了X次轟炸,每次都炸了一個每條邊都與邊界平行的矩形。

題目描述

在轟炸后,有Y個關鍵點,指揮官想知道,它們有沒有受到過轟炸,如果有,被炸了幾次,最后一次是第幾輪。

輸入格式

第一行,四個整數:n、m、x、y。

以下x行,每行四個整數:x1、y1、x2、y2,表示被轟炸的矩形的左上角坐標和右下角坐標(比如1 3 7 10就表示被轟炸的地方是從(1,3)到(7,10)的矩形)。

再以下y行,每行兩個整數,表示這個關鍵點的坐標。

輸出格式

共y行,每行第一個字符為Y或N,表示是否被轟炸,若為Y,在一個空格后為兩個整數,表示被炸了幾次和最后一次是第幾輪。

輸入輸出樣例

輸入 #1

10 10 2 3
1 1 5 5
5 5 10 10
3 2
5 5
7 1

輸出 #1

Y 1 1
Y 2 2
N

說明/提示

數據很弱!!!直接模擬!!!!
\(1 \le N,M \le 100\)

我的思路

題的思路和上一題差不多,不過將地圖數組多開了一維,以記錄需要輸出的數據。

AC代碼

#include<stdio.h>
int n, m, x, y;
int mp[105][105][2];  //記錄轟炸次數 

int main(){
	scanf("%d%d%d%d", &n, &m, &x, &y);
	int x1[x], y1[x], x2[x], y2[x], px[y], py[y];
	for(int i=0; i<x; i++){
		scanf("%d%d%d%d", &x1[i], &y1[i], &x2[i], &y2[i]);
	}
	for(int i=0; i<y; i++){
		scanf("%d%d", &px[i], &py[i]);
	}
	//開始模擬轟炸 
	for(int i=0; i<x; i++){
		for(int j=x1[i]; j<=x2[i]; j++){
			for(int k=y1[i]; k<=y2[i]; k++){
				mp[j][k][0]++;		//記錄轟炸次數 
				mp[j][k][1] = i+1;  //記錄最后一次轟炸是第幾輪 
			}
		}
	}
	//模擬完畢
	for(int i=0; i<y; i++){
		int tx = px[i];
		int ty = py[i];
		if(mp[tx][ty][0] != 0){
			printf("Y %d %d", mp[tx][ty][0], mp[tx][ty][1]);
		}
		else{
			printf("N");	
		}
		if(i+1<y){
			printf("\n");  //防止最后一行多輸回車 
		}
	} 
	
	return 0;
}

P1789 【Mc生存】插火把

題目描述

話說有一天 linyorson 在“我的世界”開了一個 \(n\times n(n\le 100)\) 的方陣,現在他有 m 個火把和 k 個螢石,分別放在 \((x_1,y_1)...(x_m,y_m)\)\((o_1,p_1)...(o_k,p_k)\) 的位置,沒有光或沒放東西的地方會生成怪物。請問在這個方陣中有幾個點會生成怪物?

P.S.火把的照亮范圍是:

    |暗|暗| 光 |暗|暗|
    |暗|光| 光 |光|暗|
    |光|光|火把|光|光|
    |暗|光| 光 |光|暗|
    |暗|暗| 光 |暗|暗|

螢石:

    |光|光| 光 |光|光|
    |光|光| 光 |光|光|
    |光|光|螢石|光|光|
    |光|光| 光 |光|光|
    |光|光| 光 |光|光|

輸入格式

輸入共m+k+1行。

第一行為n,m,k。

第2到第m+1行分別是火把的位置 \(x_i, y_i\)

第m+2到第m+k+1行分別是螢石的位置 \(o_i, p_i\)

注:可能沒有螢石,但一定有火把。

所有數據保證在int范圍內。

輸出格式

有幾個點會生出怪物。

輸入輸出樣例

輸入 #1

5 1 0
3 3

輸出 #1

12

我的思路

本題可以模擬照亮地圖的過程,計數照亮多少個單位,然后再用總面積減去照亮面積。

火把照亮區域不規則,我一開始用的是循環3*3加上4個賦值語句,最后還搜了一整遍地圖計答案,結果有兩個測試樣例超時了。

下面的是經我修改后的第二版代碼,減少了一些耗時,順利通過。

AC代碼

#include<cstdio>
int n, m, k, ans;
bool mp[105][105];
int f[13][2] = {{0, -2}, {-1, -1}, {0, -1}, {1, -1}, 
			 {-2, 0}, {-1, 0}, {0, 0}, {1, 0}, {2, 0},
			 {-1, 1}, {0, 1}, {1, 1}, {0, 2}};
			 
bool in(int x, int y){
	return 0<x && x<=n && 0<y && y<=n;
}

int main(){
	scanf("%d%d%d", &n, &m, &k);
	int fx, fy, sx, sy;  //fx, fy表示火把坐標;sx, sy表示螢石坐標 
	//開始模擬照亮地圖 
	for(int i=0; i<m; i++){
		scanf("%d%d", &fx, &fy);
		for(int j=0; j<13; j++){
			int x = fx + f[j][0];
			int y = fy + f[j][1];
			if(in(x, y)){
				if(!mp[x][y]){
					mp[x][y] = true;
					ans++;
				}
			}
		}
	}
	for(int i=0; i<k; i++){
		scanf("%d%d", &sx, &sy);
		for(int x=sx-2; x>0 && x<=sx+2 && x<=n; x++){
			for(int y=sy-2; y>0 && y<=sy+2 && y<=n; y++){  //螢石范圍 
				if(!mp[x][y]){
					mp[x][y] = true;
					ans++;
				}
			}
		}
	}
	//模擬結束,計算結果
	ans = n*n - ans;

	printf("%d", ans);
	
	return 0; 
}

---2020/7/31---


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM