1. 程式人生 > >第九屆藍橋杯c/c++ b組

第九屆藍橋杯c/c++ b組

過去水了一下,然後三等就滾回來了,現在看了看,我覺得我當時應該是思想出了問題,對面題目一直在我腦子了,他為什麼總難兩級啊

目錄

第一題:第幾天

第二題:明碼

第三題:乘積尾零

第四題:測試次數

第五題:快速排序。

第六題:遞增三元組

第七題:螺旋折線

第八題:日誌統計

第九題:全球變暖

第十題:乘積最大


第一題:第幾天

2000年的1月1日,是那一年的第1天。

那麼,2000年的5月4日,是那一年的第幾天?

注意:需要提交的是一個整數,不要填寫任何多餘內容。

 

開啟excel

答案就125了

 

第二題:明碼

漢字的字形存在於字型檔中,即便在今天,16點陣的字型檔也仍然使用廣泛。

16點陣的字型檔把每個漢字看成是16x16個畫素資訊。並把這些資訊記錄在位元組中。

一個位元組可以儲存8位資訊,用32個位元組就可以存一個漢字的字形了。

把每個位元組轉為2進製表示,1表示墨跡,0表示底色。每行2個位元組, 
一共16行,佈局是:

第1位元組,第2位元組
第3位元組,第4位元組
....
第31位元組, 第32位元組
  • 1
  • 2
  • 3
  • 4
  • 5

這道題目是給你一段多個漢字組成的資訊,每個漢字用32個位元組表示,這裡給出了位元組作為有符號整數的值。

題目的要求隱藏在這些資訊中。你的任務是復原這些漢字的字形,從中看出題目的要求,並根據要求填寫答案。

這段資訊是(一共10個漢字):

4 0 4 0 4 0 4 32 -1 -16 4 32 4 32 4 32 4 32 4 32 8 32 8 32 16 34 16 34 32 30 -64 0  
16 64 16 64 34 68 127 126 66 -124 67 4 66 4 66 -124 126 100 66 36 66 4 66 4 66 4 126 4 66 40 0 16  
4 0 4 0 4 0 4 32 -1 -16 4 32 4 32 4 32 4 32 4 32 8 32 8 32 16 34 16 34 32 30 -64 0  
0 -128 64 -128 48 -128 17 8 1 -4 2 8 8 80 16 64 32 64 -32 64 32 -96 32 -96 33 16 34 8 36 14 40 4  
4 0 3 0 1 0 0 4 -1 -2 4 0 4 16 7 -8 4 16 4 16 4 16 8 16 8 16 16 16 32 -96 64 64  
16 64 20 72 62 -4 73 32 5 16 1 0 63 -8 1 0 -1 -2 0 64 0 80 63 -8 8 64 4 64 1 64 0 -128  
0 16 63 -8 1 0 1 0 1 0 1 4 -1 -2 1 0 1 0 1 0 1 0 1 0 1 0 1 0 5 0 2 0  
2 0 2 0 7 -16 8 32 24 64 37 -128 2 -128 12 -128 113 -4 2 8 12 16 18 32 33 -64 1 0 14 0 112 0  
1 0 1 0 1 0 9 32 9 16 17 12 17 4 33 16 65 16 1 32 1 64 0 -128 1 0 2 0 12 0 112 0  
0 0 0 0 7 -16 24 24 48 12 56 12 0 56 0 -32 0 -64 0 -128 0 0 0 0 1 -128 3 -64 1 -128 0 0 

注意:需要提交的是一個整數,不要填寫任何多餘內容。

負數用的是補碼,然後就是把二進位制打出來看了 

#include<iostream>
#include<bitset>
#include<string>
using namespace std;
void printBit(const int &n) {
	for (int i = 7; i >=0; --i)
		printf("%d", (n&(1 << i)) >> i);
}
int main() {
	int n, m;
	string s1, s2;
	while (scanf("%d%d", &n, &m) != EOF) {
		/*
		用bitset
		bitset<8> a(n), b(m);
		s1 = a.to_string();
		s2 = b.to_string();
		cout << s1 << s2 << endl;
		*/
		//用正常方法
		printBit(n);
		printBit(m);
		printf("\n");
	}
	return 0;
}

 

下面的是一行一行輸入的,然後下面的結果用黑底的(比如編譯器)看比較清楚,內容是九的九次方等於多少?

4 0 4 0 4 0 4 32 -1 -16 4 32 4 32 4 32 4 32 4 32 8 32 8 32 16 34 16 34 32 30 -64 0
0000010000000000
0000010000000000
0000010000000000
0000010000100000
1111111111110000
0000010000100000
0000010000100000
0000010000100000
0000010000100000
0000010000100000
0000100000100000
0000100000100000
0001000000100010
0001000000100010
0010000000011110
1100000000000000
16 64 16 64 34 68 127 126 66 -124 67 4 66 4 66 -124 126 100 66 36 66 4 66 4 66 4 126 4 66 40 0 16
0001000001000000
0001000001000000
0010001001000100
0111111101111110
0100001010000100
0100001100000100
0100001000000100
0100001010000100
0111111001100100
0100001000100100
0100001000000100
0100001000000100
0100001000000100
0111111000000100
0100001000101000
0000000000010000
4 0 4 0 4 0 4 32 -1 -16 4 32 4 32 4 32 4 32 4 32 8 32 8 32 16 34 16 34 32 30 -64 0
0000010000000000
0000010000000000
0000010000000000
0000010000100000
1111111111110000
0000010000100000
0000010000100000
0000010000100000
0000010000100000
0000010000100000
0000100000100000
0000100000100000
0001000000100010
0001000000100010
0010000000011110
1100000000000000
0 -128 64 -128 48 -128 17 8 1 -4 2 8 8 80 16 64 32 64 -32 64 32 -96 32 -96 33 16 34 8 36 14 40 4
0000000010000000
0100000010000000
0011000010000000
0001000100001000
0000000111111100
0000001000001000
0000100001010000
0001000001000000
0010000001000000
1110000001000000
0010000010100000
0010000010100000
0010000100010000
0010001000001000
0010010000001110
0010100000000100
4 0 3 0 1 0 0 4 -1 -2 4 0 4 16 7 -8 4 16 4 16 4 16 8 16 8 16 16 16 32 -96 64 64
0000010000000000
0000001100000000
0000000100000000
0000000000000100
1111111111111110
0000010000000000
0000010000010000
0000011111111000
0000010000010000
0000010000010000
0000010000010000
0000100000010000
0000100000010000
0001000000010000
0010000010100000
0100000001000000
16 64 20 72 62 -4 73 32 5 16 1 0 63 -8 1 0 -1 -2 0 64 0 80 63 -8 8 64 4 64 1 64 0 -128
0001000001000000
0001010001001000
0011111011111100
0100100100100000
0000010100010000
0000000100000000
0011111111111000
0000000100000000
1111111111111110
0000000001000000
0000000001010000
0011111111111000
0000100001000000
0000010001000000
0000000101000000
0000000010000000
0 16 63 -8 1 0 1 0 1 0 1 4 -1 -2 1 0 1 0 1 0 1 0 1 0 1 0 1 0 5 0 2 0
0000000000010000
0011111111111000
0000000100000000
0000000100000000
0000000100000000
0000000100000100
1111111111111110
0000000100000000
0000000100000000
0000000100000000
0000000100000000
0000000100000000
0000000100000000
0000000100000000
0000010100000000
0000001000000000
2 0 2 0 7 -16 8 32 24 64 37 -128 2 -128 12 -128 113 -4 2 8 12 16 18 32 33 -64 1 0 14 0 112 0
0000001000000000
0000001000000000
0000011111110000
0000100000100000
0001100001000000
0010010110000000
0000001010000000
0000110010000000
0111000111111100
0000001000001000
0000110000010000
0001001000100000
0010000111000000
0000000100000000
0000111000000000
0111000000000000
1 0 1 0 1 0 9 32 9 16 17 12 17 4 33 16 65 16 1 32 1 64 0 -128 1 0 2 0 12 0 112 0
0000000100000000
0000000100000000
0000000100000000
0000100100100000
0000100100010000
0001000100001100
0001000100000100
0010000100010000
0100000100010000
0000000100100000
0000000101000000
0000000010000000
0000000100000000
0000001000000000
0000110000000000
0111000000000000
0 0 0 0 7 -16 24 24 48 12 56 12 0 56 0 -32 0 -64 0 -128 0 0 0 0 1 -128 3 -64 1 -128 0 0
0000000000000000
0000000000000000
0000011111110000
0001100000011000
0011000000001100
0011100000001100
0000000000111000
0000000011100000
0000000011000000
0000000010000000
0000000000000000
0000000000000000
0000000110000000
0000001111000000
0000000110000000
0000000000000000 

答案是387420489

第三題:乘積尾零

如下的10行資料,每行有10個整數,請你求出它們的乘積的末尾有多少個零?

5650 4542 3554 473 946 4114 3871 9073 90 4329  
2758 7949 6113 5659 5245 7432 3051 4434 6704 3594  
9937 1173 6866 3397 4759 7557 3070 2287 1453 9899  
1486 5722 3135 1170 4014 5510 5120 729 2880 9019  
2049 698 4582 4346 4427 646 9742 7340 1230 7683  
5693 7015 6887 7381 4172 4341 2909 2027 7355 5649  
6701 6645 1671 5978 2704 9926 295 3125 3878 6785  
2066 4247 4800 1578 6652 4616 1113 6205 3264 2915  
3966 5291 2904 1285 2193 1428 2265 8730 9436 7074  
689 5510 8243 6114 337 4096 8199 7313 3685 211 

只有2和5能產生0,所以計算2和5的因子,取比較小的那個 

#include<iostream>
int main() {
	int cnt2 = 0, cnt5 = 0, n;
	while (scanf("%d", &n) != EOF) {
		while (n % 2 == 0) {
			++cnt2;
			n >>= 1;
		}
		while (n % 5 == 0) {
			++cnt5;
			n /= 5;
		}
	}
	printf("%d\n", cnt5 < cnt2 ? cnt5 : cnt2);
	return 0;
}

答案是31

第四題:測試次數

x星球的居民脾氣不太好,但好在他們生氣的時候唯一的異常舉動是:摔手機。

各大廠商也就紛紛推出各種耐摔型手機。x星球的質監局規定了手機必須經過耐摔測試,並且評定出一個耐摔指數來,之後才允許上市流通。

x星球有很多高聳入雲的高塔,剛好可以用來做耐摔測試。塔的每一層高度都是一樣的,與地球上稍有不同的是,他們的第一層不是地面,而是相當於我們的2樓。

如果手機從第7層扔下去沒摔壞,但第8層摔壞了,則手機耐摔指數=7。

特別地,如果手機從第1層扔下去就壞了,則耐摔指數=0。

如果到了塔的最高層第n層扔沒摔壞,則耐摔指數=n

為了減少測試次數,從每個廠家抽樣3部手機參加測試。

某次測試的塔高為1000層,如果我們總是採用最佳策略,在最壞的運氣下最多需要測試多少次才能確定手機的耐摔指數呢?

請填寫這個最多測試次數。

注意:需要填寫的是一個整數,不要填寫任何多餘內容。

 

這題我當時就直接二分了,現在才發現不能二分,只有3部手機,二分早涼了,這是個dp題

#include<iostream>
int min(const int &a, const int &b) {
	return a <= b ? a : b;
}
int max(const int &a, const int &b) {
	return a >= b ? a : b;
}
int main() {
	const int N = 1005;
	//dp[i][j]代表第i層,擁有j部手機要測dp[i][j]次
	int dp[N][4] = {};
	//只有1部手機只能一層層往上測
	for (int i = 1; i <= 1000; ++i)dp[i][1] = i;
	//在第一層當然只要1次
	for (int i = 1; i < 4; ++i)dp[1][i] = 1;
	for (int i = 1; i <= 1000; ++i) 
		for (int j = 2; j < 4; ++j) {
			//初始化一個很大的值
			dp[i][j] = 0x3f3f3f3f;
			//列舉從那一層摔,如果壞了就從dp[k-1][j-1]開始,如果沒壞,就要測比k高的樓層
			for (int k = 1; k <= i; ++k)
				dp[i][j] = min(dp[i][j], max(dp[k - 1][j - 1], dp[i - k][j]) + 1);
		}
	printf("%d\n", dp[1000][3]);
	return 0;
}

答案是19

第五題:快速排序。

以下程式碼可以從陣列a[]中找出第k小的元素。

它使用了類似快速排序中的分治演算法,期望時間複雜度是O(N)的。

請仔細閱讀分析原始碼,填寫劃線部分缺失的內容。

#include <stdio.h>

int quick_select(int a[], int l, int r, int k) {
    int p = rand() % (r - l + 1) + l;
    int x = a[p];
    {int t = a[p]; a[p] = a[r]; a[r] = t;}
    int i = l, j = r;
    while(i < j) {
        while(i < j && a[i] < x) i++;
        if(i < j) {
            a[j] = a[i];
            j--;
        }
        while(i < j && a[j] > x) j--;
        if(i < j) {
            a[i] = a[j];
            i++;
        }
    }
    a[i] = x;
    p = i;
    if(i - l + 1 == k) return a[i];
    if(i - l + 1 < k) return quick_select( _____________________________ ); //填空
    else return quick_select(a, l, i - 1, k);
}

int main()
{
    int a[] = {1, 4, 2, 8, 5, 7, 23, 58, 16, 27, 55, 13, 26, 24, 12};
    printf("%d\n", quick_select(a, 0, 14, 5));
    return 0;
}

 這道題的其實沒坑,裸的快排,主要是數字1和字母l(小寫的L)太像了,所以我看了半天感覺哪裡不對

答案a, i+1, r, k-(i-l+1)

第六題:遞增三元組

給定三個整數陣列

A = [A1, A2, … AN],

B = [B1, B2, … BN],

C = [C1, C2, … CN],

請你統計有多少個三元組(i, j, k) 滿足:

1. 1 <= i, j, k <= N 
2. Ai < Bj < Ck

【輸入格式】 第一行包含一個整數N。 第二行包含N個整數A1, A2, ... AN。 第三行包含N個整數B1, B2, ... BN。 第四行包含N個整數C1, C2, ... CN。 對於30%的資料,1 <= N <= 100 對於60%的資料,1 <= N <= 1000 對於100%的資料,1 <= N <= 100000 0 <= Ai, Bi, Ci <= 100000

【輸出格式】 一個整數表示答案

【樣例輸入】

1 1 1 

2 2 2 

3 3 3 

【樣例輸出】

27

 

我當時看的時候以為i<j<k,現在腦子清楚了,其實就3個分別排序,然後列舉b,看看a有幾個小於他的,c有多少個大於他的,查詢的時候用二分,相乘就好了,最後求和就是答案了

 

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 100005;
int a[N], b[N], c[N], n;
int main() {
	scanf("%d", &n);
	for (int i = 0; i < n; ++i)scanf("%d", &a[i]);
	for (int i = 0; i < n; ++i)scanf("%d", &b[i]);
	for (int i = 0; i < n; ++i)scanf("%d", &c[i]);
	sort(a, a + n);
	sort(b, b + n);
	sort(c, c + n);
	long long sum = 0;
	for (int i = 0; i < n; ++i) {
		int x = lower_bound(a, a + n, b[i]) - a;
		int y = n - (upper_bound(c, c + n, b[i]) - c);
		sum += 1LL * x*y;
	}
	printf("%lld\n", sum);
	return 0;
}

 

第七題:螺旋折線

如圖p1.png所示的螺旋折線經過平面上所有整點恰好一次。

對於整點(X, Y),我們定義它到原點的距離dis(X, Y)是從原點到(X, Y)的螺旋折線段的長度。

例如dis(0, 1)=3, dis(-2, -1)=9

給出整點座標(X, Y),你能計算出dis(X, Y)嗎?

【輸入格式】 X和Y 對於40%的資料,-1000 <= X, Y <= 1000 對於70%的資料,-100000 <= X, Y <= 100000 對於100%的資料, -1000000000 <= X, Y <= 1000000000

【輸出格式】 輸出dis(X, Y)  

【樣例輸入】

0 1

【樣例輸出】

3

 

找規律題,雖然當時沒找到,現在想想,應該要那些座標軸上的點,比如(x,0),(0,y),

當y>=0&&abs(x)<=y時,dis(x,y)=dis(0,y)+x=(1+1+2+2+...+2y-1+2y-1)+y+x=2(1+2y-1)*(2y-1)/2+y+x=4y^2-y+x

否則當x<0&&x+1<=y<=-x時dis(x,y)=dis(x,0)+y=(1+1+2+2+...2y-1+2y-1)+x+y=2(1+2(-x)-1)*(2(-x)-1)/2+x+y=4x^2+3x+y

否則當x>0&&-x<=y<=x時dis(x,y)=dis(x,0)-y=(1+1+2+2+....2x+2x)-x-y=2*(1+2x)*(2x)/2-x-y=4x^2+x-y

否則當y<0&&-abs(x)+1>=y時dis(x,y)=dis(0,y)-x=(1+1+2+2+...(-2y)+(-2y))*(-2y)-y-x=(1-2y)*(-2y)-y-x=4y^2-3y-x

#include<iostream>
#include<cmath>
int main() {
	long long x, y;
	scanf("%lld%lld", &x, &y);
	if (y >= 0 && abs(x) <= y)printf("%lld\n", 4 * y*y - y + x);
	else if (x < 0 && x + 1 <= y && y <= -x)printf("%lld\n", 4 * x*x + 3 * x + y);
	else if (x > 0 && -x <= y && y <= x)printf("%lld\n", 4 * x*x + x - y);
	else printf("%lld\n", 4 * y*y - 3 * y - x);
	return 0;
}

第八題:日誌統計

小明維護著一個程式設計師論壇。現在他收集了一份”點贊”日誌,日誌共有N行。其中每一行的格式是:

ts id

表示在ts時刻編號id的帖子收到一個”贊”。

現在小明想統計有哪些帖子曾經是”熱帖”。如果一個帖子曾在任意一個長度為D的時間段內收到不少於K個贊,小明就認為這個帖子曾是”熱帖”。

具體來說,如果存在某個時刻T滿足該帖在[T, T+D)這段時間內(注意是左閉右開區間)收到不少於K個贊,該帖就曾是”熱帖”。

給定日誌,請你幫助小明統計出所有曾是”熱帖”的帖子編號。

【輸入格式】 第一行包含三個整數N、D和K。 以下N行每行一條日誌,包含兩個整數ts和id。 對於50%的資料,1 <= K <= N <= 1000 對於100%的資料,1 <= K <= N <= 100000 0 <= ts <= 100000 0 <= id <= 100000

【輸出格式】 按從小到大的順序輸出熱帖id。每個id一行。

【輸入樣例】

7 10 2 

0 1 

0 10 

10 10 

10 1 

9 1 

100 3 

100 3 

【輸出樣例】

1 3

 

其實就是暴力+尺取法

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
const int N = 100005;
int d, k;
vector<int> t[N];
bool judge(const int &id) {
	int len = t[id].size();
	if (len < k)return false;
	sort(t[id].begin(), t[id].end());
	int L = 0, R = 0, sum = 0;
	while (L <= R && R < len) {
		++sum;
		if (sum >= k) {
			if (t[id][R] - t[id][L] < d)return true;
			++L;
			--sum;
		}
		++R;
	}
	return false;
}
int main() {

	int n, ts, id, ans[N], cnt = 0;
	scanf("%d%d%d", &n, &d, &k);
	for (int i = 0; i < n; ++i) {
		scanf("%d%d", &ts, &id);
		t[id].push_back(ts);
	}
	for (int i = 0; n && i < N; ++i, --n)
		if (judge(i)) {
			ans[cnt] = i;
			++cnt;
		}
	for (int i = 0; i < cnt; ++i)printf("%d\n", ans[i]);
	return 0;
}

 

第九題:全球變暖

你有一張某海域NxN畫素的照片,”.”表示海洋、”#”表示陸地,如下所示:

……. 
.##…. 
.##…. 
….##. 
..####. 
…###. 
…….

其中”上下左右”四個方向上連在一起的一片陸地組成一座島嶼。例如上圖就有2座島嶼。

由於全球變暖導致了海面上升,科學家預測未來幾十年,島嶼邊緣一個畫素的範圍會被海水淹沒。具體來說如果一塊陸地畫素與海洋相鄰(上下左右四個相鄰畫素中有海洋),它就會被淹沒。

例如上圖中的海域未來會變成如下樣子:

……. 
……. 
……. 
……. 
….#.. 
……. 
…….

請你計算:依照科學家的預測,照片中有多少島嶼會被完全淹沒。

【輸入格式】 第一行包含一個整數N。 (1 <= N <= 1000) 以下N行N列代表一張海域照片。 照片保證第1行、第1列、第N行、第N列的畫素都是海洋。

【輸出格式】 一個整數表示答案。

【輸入樣例】

....... 

.##.... 

.##.... 

....##. 

..####. 

...###. 

....... 

【輸出樣例】

1

 

個人感覺看到的答案都是錯的,但是我的答案也不敢保證是對的

思路:我認為,第一遍遍歷,看到沒訪問過的#就bfs島嶼,把與海相鄰的標記為1,否則標記為2,然後再遍歷一遍,看到標記為1的就bfs島嶼,看看bfs過程中有沒有2,如果有,說明沒被腐蝕,否則腐蝕了,cnt++

個人案例(看到的答案都死迴圈了)

【輸入樣例】

....... 

.##.... 

.##.... 

...#### 

..##### 

...#### 

....... 

【輸出樣例】

1

#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
class point {
public:
	int x, y;
	point(const int &x = 0, const int &y = 0) :x(x), y(y) {}
};
const int N = 1005, dir[4][2] = { -1,0,1,0,0,-1,0,1 };
char map[N][N];
int visit[N][N], n, cnt;
void bfs(const int &sx,const int &sy) {
	queue<point> q;
	q.push(point(sx, sy));
	while (!q.empty()) {
		point temp = q.front();
		int x = temp.x;
		int y = temp.y;
		q.pop();
		for (int i = 0; i < 4; ++i) {
			int xx = x + dir[i][0];
			int yy = y + dir[i][1];
			if (xx < 0 || xx >= n || yy < 0 || yy >= n)continue;
			if (map[xx][yy] == '.') {
				visit[x][y] = 1;
				break;
			}
		}
		for (int i = 0; i < 4; ++i) {
			int xx = x + dir[i][0];
			int yy = y + dir[i][1];
			if (xx < 0 || xx >= n || yy < 0 || yy >= n||map[xx][yy]!='#'||visit[xx][yy])continue;
			visit[xx][yy] = 2;
			q.push(point(xx, yy));
		}
	}
}
void bfs2(const int &sx, const int &sy) {
	queue<point> q;
	q.push(point(sx, sy));
	bool flag = true;
	while (!q.empty()) {
		point temp = q.front();
		int x = temp.x;
		int y = temp.y;
		map[x][y] = '.';
		q.pop();
		for (int i = 0; i < 4; ++i) {
			int xx = x + dir[i][0];
			int yy = y + dir[i][1];
			if (xx < 0 || xx >= n || yy < 0 || yy >= n || map[xx][yy] != '#' || !visit[xx][yy])continue;
			if (visit[xx][yy] == 2)flag = false;
			q.push(point(xx, yy));
		}
	}
	if (flag)++cnt;
}
int main() {
	scanf("%d", &n);
	for (int i = 0; i < n; ++i)scanf("%s", map[i]);
	for (int i = 0; i < n; ++i) {
		for (int j = 0; j < n; ++j) {
			if (map[i][j] == '#' && !visit[i][j]) {
				bfs(i, j);
			}
		}
	}
	for (int i = 0; i < n; ++i) {
		for (int j = 0; j < n; ++j) {
			if (map[i][j] == '#'&&visit[i][j] == 1) {
				bfs2(i, j);
			}
		}
	}
	printf("%d\n", cnt);
	return 0;
}

第十題:乘積最大

給定N個整數A1, A2, … AN。請你從中選出K個數,使其乘積最大。

請你求出最大的乘積,由於乘積可能超出整型範圍,你只需輸出乘積除以1000000009的餘數。

注意,如果X<0, 我們定義X除以1000000009的餘數是負(-X)除以1000000009的餘數。

即:0-((0-x) % 1000000009)

【輸入格式】 第一行包含兩個整數N和K。 以下N行每行一個整數Ai。 對於40%的資料,1 <= K <= N <= 100 對於60%的資料,1 <= K <= 1000 對於100%的資料,1 <= K <= N <= 100000 -100000 <= Ai <= 100000

【輸出格式】 一個整數,表示答案。

【輸入樣例】

5 3 

-100000 

-10000 

100000 

10000 

【輸出樣例】

999100009

 再例如: 【輸入樣例】

5 3 

-100000 

-100000 

-2 

-100000 

-100000 

【輸出樣例】

-999999829

 

這個取餘規則沒有什麼卵用,按平常的取餘就行了

去掉0之後,按絕對值大小排序

如果數量小於k,輸出0

如果全正,取前面k個

如果全負 

               如果k是奇數,取後面k個,否則取前面k個

如果有正有負

               如果前k個裡面有偶數個負數,取前面k個

                否則用前k箇中較小的正數換後面n-k箇中絕對值最大的負數,去比較前k箇中較小的負數換後面n-k箇中絕對值最大的正數,取前k個相乘後結果較大的,如果還是小於0,就取後面k個

 

最後結果還是小於0,看看有沒有0,有就取0

#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 100000, mod = 1000000009;
int a[N], n, k;
ll max(const ll &a, const ll &b) { return a >= b ? a : b; }
bool cmp(const int &a, const int &b) {
	return abs(a) > abs(b);
}
ll getAns(const bool &front) {
	ll ans = 1;
	if (front)
		for (int i = 0; i < k; ++i)ans = ans * a[i] % mod;
	else
		for (int i = n - 1; i >= n - k; --i)ans = ans * a[i] % mod;
	return ans;
}
int main() {
	bool contain_zero = false;
	int cnt1 = 0, cnt2 = 0;
	scanf("%d%d", &n, &k);
	for (int i = 0; i < n; ++i) {
		scanf("%d", &a[i]);
		if (!a[i]) {
			--n;
			--i;
			contain_zero = true;
		}
		else if (a[i] > 0)++cnt1;
		else ++cnt2;
	}
	sort(a, a + n, cmp);
	ll ans;
	if (n < k)ans = 0;
	else if (cnt2 == n) {
		if (k & 1)ans = getAns(false);
		else ans = getAns(true);
	}
	else if (cnt1 == n)ans = getAns(true);
	else {
		int cntMinus = 0;
		for (int i = 0; i < k; ++i)
			if (a[i] < 0)++cntMinus;
		if (cntMinus % 2 == 0)ans = getAns(true);
		else {
			int p = -1, q = -1;
			for (int i = k-1; i >= 0; --k)
				if (a[i] < 0) {
					p = i;
					break;
				}
			for (int i = k; i < n; ++i)
				if (a[i] > 0) {
					q = i;
					break;
				}
			if (p != -1 && q != -1) {
				swap(a[p], a[q]);
				ans = getAns(true);
				swap(a[p], a[q]);
			}
			p = q = -1;
			for (int i = k - 1; i >= 0; --k)
				if (a[i] > 0) {
					p = i;
					break;
				}
			for (int i = k; i < n; ++i)
				if (a[i] < 0) {
					q = i;
					break;
				}
			if (p != -1 && q != -1) {
				swap(a[p], a[q]);
				ans = max(getAns(true), ans);
				swap(a[p], a[q]);
			}
			if (ans < 0)ans = getAns(false);
		}
	}
	if (ans < 0 && contain_zero)ans = 0;
	printf("%lld\n", ans);
	return 0;
}