1. 程式人生 > 實用技巧 >初二普及組全真模擬賽 前三題題解

初二普及組全真模擬賽 前三題題解

數你太美【第一週】

題目描述

PB 獲得了兩個正整數數列 \({a_i}\) , \({b_i}\) ,長度分別為 n , m ,其中每個數都小於 10。 定義一個正整數是“美麗的正整數”,當且僅當:這個數的十進位制表示中,至少有一個 數位上的數在數列 a_i 出現過,至少有一個數位上的數在數列 b_i 出現過。現在 PB 希 望求出最小的“美麗的正整數”。

輸入格式

第一行,兩個正整數 n , m ;

第二行,n 個正整數,第 i 個為 a_i ;

第三行,m 個正整數,第 i 個為 b_i 。

輸出格式

一行,一個正整數表示最小的“美麗的正整數”。

樣例

樣例輸入
樣例輸入 1

2 3
2 4
6 5 2

樣例輸出 1

2

樣例解釋 1

2 既在數列 a 中出現又在數列 b 中出現,且可知沒有比 2 小的正整數是“美麗的正整 數”。

樣例輸入 2

2 6
8 7
1 1 4 5 1 4

樣例輸出 2

17

樣例解釋 2:

17 中有數位 1,7 。1 在數列 b 中出現, 7 在數列 a 中出現,且可以證明沒有比 17 小 的正整數是“美麗的正整數”。

資料範圍與提示

對於 30% 的資料, \(1<=n,m<=4;\)
對於 100% 的資料, \(1<=n,m<=9,1<=a_i,b_i<=9。\)

分析

首先已知所有的\(a_i\)\(b_i\)都不會大於9,則可知道組合的“美麗的正整數”一定沒有單獨的“美麗的正整數”優。
不難想出方法,先排序,遍歷兩個陣列,如果有相同元素,則直接輸出並退出,否則就比較兩個序列的最小值,將其組成兩位數輸出。

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int MAXN = 105;
const int INF = 0x3f3f3f3f;

int n, m, a[MAXN], b[MAXN], ans;
bool flag;

int main() {
    scanf("%d %d", &n, &m);
    for (int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
    }
    for (int i = 1; i <= m; i++) {
        scanf("%d", &b[i]);
    }
    sort(a + 1, a + 1 + n);
    sort(b + 1, b + 1 + m);
    ans = 0x3f3f3f3f;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            if (a[i] == b[j]) {
                ans = min(ans, a[i]);
                flag = 1;
            }
        }
    }
    if (flag)
        printf("%d\n", ans);
    else {
        printf("%d%d\n", min(a[1], b[1]), max(a[1], b[1]));
    }
    return 0;
}

逃亡【第一週】

題目描述

從前有個平面直角座標系,座標系裡有座學校。這是一個矩形,左下角是 (0,0),右上角是 (n,m)。有 k 個蒟蒻在校園中。第 i 個蒟蒻在 (xi,yi) 的位置。由於一些不可 抗因素,所有 xi 互不相同,所有 yi 互不相同。這時 PB 要來抓蒟蒻們做實驗了!

蒟蒻們聽到這個訊息,也是四處逃亡,只要逃到校園的邊界上就不會被 PB 抓到。 每個蒟蒻可以沿著任意路線逃亡。然而蒟蒻們反應遲鈍,所以如果兩個蒟蒻的逃亡路線 有交點,它們就有可能相撞,就會被 PB 抓住。所以任意兩人的路線不能有交點。

現在蒟蒻們想知道,蒟蒻全部能成功逃亡的路線的長度之和的最小值。(雖然,這 對神通廣大的 PB 根本不是一回事......)

輸入格式

第一行三個整數 n, m, k,相鄰兩數用一個空格分開。

接下來 k 行,第 i 行兩個正整數 xi 和 yi,用一個空格分開。

輸出格式

一行一個數表示總距離的最小值,保留 3 位小數。

樣例

樣例輸入

5 5 1
1 2

樣例輸出

1.000

資料範圍與提示

對於前 30% 的資料,0<=n,m<=6, 1<=k<=5。

對於前 100% 的資料,0<=n,m<=10^9, 1<=k<=5000, 1<=xi<n, 1<=yi<m

對於所有資料,xi 互不相同,yi 互不相同。

分析

開始讀題有點暈,準備想如何分配每個蒟蒻的逃跑路線,但畫圖後我發現 “任意兩人的路線不能有交點。”是一句廢話。
假設有一個點\((x, y)\),那麼在不考慮其他點的情況下,它的最優逃跑路線就是它分別到四個邊界的距離的最小值即\(Min(x, y, n - x, n - y)\)。並且此題也不需要考慮其他點

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int MAXN = 5005;

int n, m, k, x, y;
double ans;

int main() {
	scanf ("%d %d %d", &n, &m, &k);
	for (int i = 1; i <= k; i++) {
		scanf ("%d %d", &x, &y);
		x = min(x, n - x);
		y = min(y, m - y);
		ans += min(x, y);
	}
	printf ("%.3lf\n", ans);
	return 0;
} 

數數字【第一週】

題目描述

PB 帶來了若干只蒟蒻。

眾所周知,NTF 是數論學會的會長,於是 PB 準備用數字擊敗 NTF,以證明 PB 比 NTF 更強。

於是 PB 準備了一些卡片,並在每個蒟蒻頭上都貼了一張卡牌。每個卡牌上都寫了一個數字。

由於蒟蒻太弱了,甚至不會看鏡子來了解自己頭上的數字,但他們由於經常被大佬吊打,所以觀察力敏銳,他們都知道別人頭上的數字。

第 i 個蒟蒻會告訴你他看到了 ai 種數字(定義兩個數字不同種當且僅當它們的值不同)

但是由於蒟蒻太弱了,可能會報錯資料,NTF 需要核實是否有一種情況使所有蒟 蒻說的話都正確。(可能情況不唯一)

輸入格式

多組測試,檔案第一行一個整數 T,表示測試資料組數;

對於每組資料,第一行,一個整數 n,表示蒟蒻的數量;

第二行,n 個整數用空格隔開,表示陣列 ai,意義同題面。

輸出格式

如果至少有一種情況使所有蒟蒻的話都正確,輸出"yes",否則,輸出"no"。

樣例

樣例輸入

2
2
1 1
4
1 3 2 2

樣例輸出

yes
no

資料範圍與提示

對於所有資料,T<=10

對於 20% 的資料,N≤8

對於所有資料,1≦N≤1000000, 0≦ai<N

分析

一道思維題。
考試時先打了一個假暴力,考完看提交記錄有50pts,然後開始想數學解法。
打假暴力時想到了一個優化:如果這個數列中最大值與最小值已經相差了2及以上,就不用管了。
因為每個蒟蒻看到的種數是\(a_i\), 那麼總種樹無非就是\(a_i +1\)(自己頭上的數字唯一)或者\(a_i\)(自己頭上的數字不唯一,已經出現過),當兩個\(a_i\)相差2及以上是,是無論如何也無法勻平的。
繼續按思路往下走,當最大值和最小值不同時,就只有兩種情況,相差一或相等。

當最大值等於最小值的時候,分兩種情況討論,最大值等於\(n-1\)說明所有的蒟蒻的數字都是唯一的,符合條件。如果最大值的二倍小於\(n\),也滿足條件,因為每個每個蒟蒻都不唯一,所以至少有兩個蒟蒻的數字一樣,則他們可以互相看到,可以彌補上統計,正是如此,那麼也可以得知此時每個數字都有兩個重複的元素,所以最大值的二倍要小於\(n\).

那麼當他們相差一的時候,就說明有蒟蒻頭上的數字唯一(因為蒟蒻無法看到自己頭上的數字,所以會統計掉一個,但其他頭上是重複數字的蒟蒻則會把他統計上,導致相差一),用一個\(sum\)統計有多少個數字唯一的蒟蒻(即\(a_i=Min(a_1 ... a_n)\)),可得\(sum\)應該大於\(Min(a_1 ... a_n)\),因為已經得到了最大值與最小值相同時的結論,我們可以在現在的數列中去掉數字唯一的蒟蒻,那麼最大值應該小於等於\((n - sum) / 2 + sum\)

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int MAXN = 1000005;
const int INF = 0x3f3f3f3f;

int t, n, t1, t2, sum;
int a[MAXN];

int main() {
	scanf ("%d", &t);
	while (t--) {
		scanf ("%d", &n);
		t1 = INF;
		t2 = -1;
		sum = 0;
		for (int i = 1; i <= n; i++) {
			scanf ("%d", &a[i]);
			t1 = min(t1, a[i]);
			t2 = max(t2, a[i]);
		}
		if (t2 - t1 > 1) {
			printf ("no\n");
			continue;
		}
		if (t2 - t1 == 1) {
			for (int i = 1; i <= n; i++) {
				if (a[i] == t1) {
					sum ++;
				}
			}
			if (sum < t2 && t2 <= (n - sum) / 2 + sum) {
				printf ("yes\n");
				continue;
			} else {
				printf ("no\n");
				continue;
			}
		}
		if (t2 == t1) {
			if (t2 == n - 1) {
				printf ("yes\n");
				continue;
			} 
			if (t2 * 2 <= n) {
				printf ("yes\n");
				continue;
			} else {
				printf ("no\n");
				continue;
			}
		}
	}
	return 0;
}