詳細題解|藍橋杯第十一屆軟件類校內模擬賽


大綱:

1.GB*1024=MB 答案:15488
2.枚舉約數,答案:96
3.完全二叉樹最多,答案:1010(不知道有沒有看錯題,是不是二叉)
4.枚舉,判是否包含9,544
5.50%數據:3層枚舉判遞增;100%數據:思路1,枚舉中心點,查左邊<i的,查右邊>i的,總時間復雜度O(n^2);思路2:查詢可以優化,用樹狀數組查,總時間復雜度O(longn)
6.100%數據:枚舉,倒着判數字是否遞減,O(10^7) 不會超時
7.100%數據:字符串模擬
8.70%數據:按題意模擬,更新原草地;100%數據:思路1,bfs搜索;思路2:二維差分
9.50%數據:dfs暴力搜索;80%數據:記憶化搜索;100%數據:記憶化搜索+打表。
10.60%數據:按題意模擬,每次查詢前一個元素后面的元素的最大值;時間復雜度O(n^2);100%數據:思路1:按60%的思路中的查詢可以用線段樹優化,用線段樹查詢區間最大值,時間復雜度O(nlongn)

下面是詳細代碼和大題按數據點給分的各個思路:

1. 答案:15488

15.125GB*1024 = 15488MB,用計算器算一下,答案是15488


2. 答案:96

1200000有多少個約數(只計算正約數)。
枚舉1200000的約數,set去重

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn = 1e6+10;

set<int> se;
int main(){
	ll x = 1200000;
	for(ll i = 1; i <= sqrt(x); i++){
		if(x%i == 0) {
			se.insert(i);
			se.insert(x/i);
		}
	}
	cout<<se.size();
	return 0;
} 

3. 答案:未知

一棵包含有2019個結點的樹,最多包含多少個葉結點?
不記得是不是二叉樹了,如果是一顆普通的樹,那么答案是2018;
如果是一個二叉樹,那么在類滿二叉樹下,葉節點最多,答案可能是1010;(不確定)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn = 1e6+10;
int n = 2019;

int main(){
	ll sum = 0;
	int maxDeep = 0;
	for(int depth = 0;depth<=10000;depth++){ //枚舉滿二叉樹的層數
		if(sum + pow(2,depth) > n) break;
		sum += pow(2,depth);
		maxDeep = depth;
	}
	cout<<(pow(2,maxDeep) - ((n-sum)/2)) + (n-sum); //最后一層有可能不滿,那么倒數第二層有(pow(2,maxDeep) - ((n-sum)/2))個非葉子節點,再加上最后一層的葉子節點(n-sum)個
	return 0;
} 

4. 答案:544

在1至2019中,有多少個數的數位中包含數字9?
枚舉1~2019,判斷是否包含9

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn = 1e6+10;

int cnt = 0;

bool contain(int x){
	if(x == 9) return true;
	if(x<9) return false;
	while(x){
		if(x%10 == 9) return true;
		x = x/10;
	}
	return false;
}

int main(){
	for(int i=1;i<=2019;i++){
		if(contain(i)) cnt++;
	}
	cout<<cnt;
	return 0;
} 

5.

問題描述
在數列 a[1],a[2],...,a[n] 中,如果對於下標 i,j,k 滿足 0<i<j<k<n+1 且 a[i]<a[j]<a[k],則稱 a[i],a[j],a[k] 為一組遞增三元組,a[j] 為遞增三元組的中心。

給定一個數列,請問數列中有多少個元素可能是遞增三元組的中心。

輸入格式
輸入的第一行包含一個整數 n。

第二行包含 n 個整數 a[1],a[2],...,a[n] ,相鄰的整數間用空格分隔,表示給定的數列。

輸出格式
輸出一行包含一個整數,表示答案。

評測用例規模與約定
對於 50 的評測用例,2<=n<=100,0<=Num<=1000 。
對於所有評測用例,2<=n<=1000,0<=Num<=10000 。

50% 3層枚舉,判遞增

3層枚舉,只要a[i] < a[j] < a[k]說明滿足條件了

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

//50%

const int maxn = 1e5+100;
int a[maxn];
int n;
set<int> se;
int main(){
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	ll cnt = 0;
	for(int i=1;i<=n;i++){
		for(int j=i+1;j<=n;j++){
			if(a[j] > a[i]){
				for(int k=j+1;k<=n;k++){
					if(a[k] > a[j]) 
						se.insert(j);
				}
			}
		}
	}
	cout<<se.size();
	return 0;
} 

100% 枚舉中心點,O(n^2)

枚舉中心點,查左邊<i的,查右邊>i的,如果中心點左邊有比它小的數,同時中心點右邊有比它大的數,就滿足條件,總數+1。總時間復雜度O(n^2)。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

//100% 枚舉O(n^2) 

const int maxn = 1e5+100;
int a[maxn];
int n;
int main(){
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	ll cnt = 0;
	for(int center = 2;center<=n-1;center++){ //枚舉中心點 
		int leftNum = 0,rightNum = 0;
		for(int left = 1;left<center;left++){ //統計左邊比它小的 
			if(a[left] < a[center]) leftNum++;
		}
		for(int right = center+1;right<=n;right++){ //統計右邊比它大的 
			if(a[right] > a[center]) rightNum++;
		}
		if(leftNum * rightNum != 0) cnt++;
	}
	cout<<cnt;
	return 0;
} 

100% 樹狀數組優化O(nlongn)

樹狀數組維護分別正序和倒序維護各個數出現的次數,動態查詢
1.正序建樹:查詢中心點左邊比它的值小的個數,就是查此時1~i-1的數的個數
2.逆序建樹:查詢中心點右邊比它的值大的個數,就是查此時i+1~n的數的個數
3.枚舉中心點: 如果中心點左邊有比它小的數,同時中心點右邊有比它大的數,就是一個合法的中心點

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

/*
100% nlogn
樹狀數組維護分別正序和倒序維護各個數出現的次數,動態查詢 
1.正序建樹:查詢中心點左邊比它的值小的個數,就是查此時1~i-1的數的個數
2.逆序建樹:查詢中心點右邊比它的值大的個數,就是查此時i+1~n的數的個數
3.枚舉中心點: 如果中心點左邊有比它小的數,同時中心點右邊有比它大的數,就是一個合法的中心點 
*/
const int maxn = 1e5+100;
int C[maxn];
int a[maxn];
int n;
int cnt1[maxn],cnt2[maxn];

int lowbit(int x){
	return x & -x; 
} 

int getsum(int x){ //查前綴和 
	int ans = 0;
	while(x >= 1){
		ans += C[x];
		x = x - lowbit(x);
	}
	return ans;
}

void add(int x,int k){
	while(x <= n){
		C[x] = C[x] + k;
		x = x + lowbit(x);
	}
}

int query(int l,int r){ //區間查詢 
	return getsum(r) - getsum(l-1);
}


int main(){
	cin>>n;
	for(int i=1;i<=n;i++) {
		cin>>a[i];
		add(a[i],1); //正序建樹查左側比i個元素小的 
		cnt1[i] = query(1,i-1); 
	}
	memset(0,sizeof(C),0);
	for(int i=n;i>=1;i--){ //倒序建樹 查右側比第i個元素大的 
		add(a[i],1);
		cnt2[i] = query(i+1,n);
	}
	ll cnt = 0;
	for(int i=1;i<=n;i++){ //枚舉中心點 
		if(cnt1[i] && cnt2[i]) cnt++;
	}
	cout<<cnt;
	return 0;
} 
/*
5
1 2 5 3 5
*/

6.

問題描述
一個正整數如果任何一個數位不大於右邊相鄰的數位,則稱為一個數位遞增的數,例如 1135 是一個數位遞增的數,而 1024 不是一個數位遞增的數。

給定正整數 n ,請問在整數 1 至 n 中有多少個數位遞增的數?

輸入格式
輸入的第一行包含一個整數 n 。

輸出格式
輸出一行包含一個整數,表示答案。

評測用例規模與約定
對於 40% 的評測用例,1<=n<=1000。
對於 80% 的評測用例,1<=n<=100000。
對於所有評測用例,1<=n<=1000000。

100%數據:枚舉,倒着數字判遞減,O(10^7)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

//100%

const int maxn = 1e6+10;

int n;

bool solve(int x){
	if(x < 10 ) return true;
	int last = x%10;
	x = x / 10;
	while(x){
		if(x%10 > last) return false;
		last = x%10;
		x = x / 10;
	}
	return true;
}

int main(){
	cin>>n;
	ll cnt = 0;
	for(int i=1;i<=n;i++){
		if(solve(i)) cnt++;
	}
	cout<<cnt;
	return 0;
} 

7.

問題描述
小明對類似於 hello 這種單詞非常感興趣,這種單詞可以正好分為四段,第一段由一個或多個輔音字母組成,第二段由一個或多個元音字母組成,第三段由一個或多個輔音字母組成,第四段由一個或多個元音字母組成。
給定一個單詞,請判斷這個單詞是否也是這種單詞,如果是請輸出yes,否則請輸出no。
元音字母包括 a,e,i,o,u ,共五個,其他均為輔音字母。

輸入格式
輸入一行,包含一個單詞,單詞中只包含小寫英文字母。

輸出格式
輸出答案,或者為 yes ,或者為 no 。

評測用例規模與約定
對於所有評測用例,單詞中的字母個數不超過 100

100%數據 按題意字符串模擬

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn = 1e6+10;

string a;

int main(){
	cin>>a;
	int pos = 1;
	int level = 1;
	bool flag = true;
	int len = a.length();
	while(pos < len){
		if(level == 2){ //元音 
			int ago = pos;
			while(pos < len && (a[pos] == 'a'|| a[pos] == 'e' || a[pos] == 'i' || a[pos] == 'o' || a[pos] == 'u')){
				pos++; 
			} 
			if(pos == ago && !((a[pos] == 'a'|| a[pos] == 'e' || a[pos] == 'i' || a[pos] == 'o' || a[pos] == 'u'))) flag = false;
			level++;
		}else if(level == 1){  
			int ago = pos;
			while(pos < len && (a[pos] != 'a'&& a[pos] != 'e' && a[pos] != 'i' && a[pos] != 'o' && a[pos] != 'u')){
				pos++; 
			} 
			if(pos == ago && !(a[pos] != 'a'&& a[pos] != 'e' && a[pos] != 'i' && a[pos] != 'o' && a[pos] != 'u')) flag = false;
			level++;
		}else if(level == 4){ //元音 
			int ago = pos;
			while(pos < len && (a[pos] == 'a'|| a[pos] == 'e' || a[pos] == 'i' || a[pos] == 'o' || a[pos] == 'u')){
				pos++; 
			} 
			if(pos == ago && !((a[pos] == 'a'|| a[pos] == 'e' || a[pos] == 'i' || a[pos] == 'o' || a[pos] == 'u'))) flag = false;
			level++;
		}else if(level == 3){
			int ago = pos;
			while(pos < len && (a[pos] != 'a'&& a[pos] != 'e' && a[pos] != 'i' && a[pos] != 'o' && a[pos] != 'u')){
				pos++; 
			} 
			if(pos == ago && !((a[pos] != 'a'&& a[pos] != 'e' && a[pos] != 'i' && a[pos] != 'o' && a[pos] != 'u'))) flag = false;
			level++;
		}else flag = false;
		if(flag == false) break;
	}
	if(flag && level == 5) puts("yes");
	else puts("no");
	return 0;
} 

8.

問題描述
小明有一塊空地,他將這塊空地划分為 n 行 m 列的小塊,每行和每列的長度都為 1 。

小明選了其中的一些小塊空地,種上了草,其他小塊仍然保持是空地。

這些草長得很快,每個月,草都會向外長出一些,如果一個小塊種了草,則它將向自己的上、下、左、右四小塊空地擴展,這四小塊空地都將變為有草的小塊。

請告訴小明,k 個月后空地上哪些地方有草。

輸入格式
輸入的第一行包含兩個整數 n , m 。

接下來 n 行,每行包含 m 個字母,表示初始的空地狀態,字母之間沒有空格。如果為小數點,表示為空地,如果字母為 g,表示種了草。

接下來包含一個整數 k。

輸出格式
輸出 n 行,每行包含 m 個字母,表示 k 個月后空地的狀態。如果為小數點,表示為空地,如果字母為 g,表示長了草。

評測用例規模與約定
對於 30% 的評測用例,2<=n,m<=20。
對於 70% 的評測用例,2<=n,m<=100。
對於所有評測用例,2<=n,m<=1000,1<=k<=1000。

70% 模擬

按題意模擬,開一個新數組更新草地,更新完將復制給舊數組。一月更新一次。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn = 1100;

int n,m,k;
char a[maxn][maxn];
char s[maxn][maxn];

int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++) {
			cin>>a[i][j];
			s[i][j] = a[i][j];
		}
	}
	cin>>k;
	for(int i=1;i<=k;i++){
		for(int p = 1;p <= n;p++){
			for(int q = 1;q <= m;q++){
				if(a[p][q] == 'g'){
					s[p-1][q] = 'g';
					s[p+1][q] = 'g';
					s[p][q-1] = 'g';
					s[p][q+1] = 'g';
				}
			}
		}
		for(int p=1;p<=n;p++){
			for(int q=1;q<=m;q++) a[p][q] = s[p][q];
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			cout<<a[i][j];
		}
		cout<<endl;
	}
	return 0;
} 
/*
2 2
.g
..
1
*/

100% bfs搜索

把最初是'g'的坐標先入隊列,跑bfs,bfs分層的性質保證了 土地每次都是向外一次一次擴展(即:每個月用最外層的草地擴展一次),每次擴展把4個方向滿足條件的加入隊列。直到dist=k 說明從最初的g點已經走了k個距離 不能再走下去了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn = 1100;

int n,m,k;
char a[maxn][maxn]; 
struct node{
	int x,y,dist;
};
queue<node> que;

void bfs(){
	while(!que.empty()){
		node u = que.front(); //取出隊頭 
		que.pop();
		if(u.dist == k) continue; //dist=k 說明從最初的g點已經走了k個距離 不能再走下去了 
		int x = u.x,y = u.y,dist = u.dist;
		//把4個方向滿足條件的加入隊列  作一次擴展 
		if(x+1<=n && a[x+1][y] != 'g'){
			a[x+1][y] = 'g';
			que.push({x+1,y,dist+1});
		}
		if(y+1<=m && a[x][y+1] != 'g'){
			a[x][y+1] = 'g';
			que.push({x,y+1,dist+1});
		}	
		if(x-1>=1 && a[x-1][y] != 'g'){
			a[x-1][y] = 'g';
			que.push({x-1,y,dist+1});
		}
		if(y-1>=1 && a[x][y-1] != 'g'){
			a[x][y-1] = 'g';
			que.push({x,y-1,dist+1});
		}
	}
}

int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++) {
			cin>>a[i][j];
			if(a[i][j] == 'g') que.push({i,j,0}); //把最初是'g'的先入隊 
		}
	}
	cin>>k;
	bfs();//跑一遍bfs bfs分層的性質保證了 土地每次都是向外一次一次擴展(即:每個月用最外層的草地擴展一次)
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++) {
			cout<<a[i][j];
		}
		cout<<endl;
	}
	return 0;
} 
/*
4 5
.g...
..... 
..g..
.....
2
*/

100% 二維差分

每一個初始點g,影響的范圍是一個菱形,用二維差分標記
參考這道題:https://www.cnblogs.com/fisherss/p/10388172.html

9.

問題描述
小明想知道,滿足以下條件的正整數序列的數量:

第一項為 n ;
第二項不超過 n ;
從第三項開始,每一項小於前兩項的差的絕對值。
請計算,對於給定的 n ,有多少種滿足條件的序列。

輸入格式
輸入一行包含一個整數 n 。

輸出格式
輸出一個整數,表示答案。答案可能很大,請輸出答案除以 10000 的余數。

評測用例規模與約定
對於 20% 的評測用例,1<=n<=5。
對於 50% 的評測用例,1<=n<=10。
對於 80% 的評測用例,1<=n<=100。
對於所有評測用例,1<=n<=1000。

50% dfs暴力搜索

n==2的時候 有n種方案,分別可以放1~n;
dfs判n>3的情況

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

//50% dfs暴力搜索 

const int maxn = 1010;
int n;
ll cnt = 0;
int a[maxn];

void dfs(int pos,int u,int v){ //判n>3的情況
	cnt = (cnt+1)%10000;
	int d = abs(v-u);
	if(d == 0) return;
	for(int i=1;i<d;i++){
		a[pos] = i;
		dfs(pos+1,i,u);
	}
}

int main(){
	cin>>n;
	a[1] = n;
	for(int i=n;i>=1;i--){ //n==2的時候 有n種方案,分別可以放1~n
		a[2] = i;
		dfs(3,i,n);
	}
	cout<<cnt;
	return 0;
} 

80%數據 記憶化搜索

開個map作緩存,能過80%數據

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

//80% 記憶化搜索 

int n;
map<pair<int,int>,int > mp;

int dfs(int u,int v){
	if(mp[make_pair(u,v)]) return mp[make_pair(u,v)];
	int d = abs(v-u);
	if(d == 0) return mp[make_pair(u,v)] = 1;
	ll cnt = 1;
	for(int i=1;i<d;i++){
		cnt = (cnt + dfs(i,u))%10000;
	}
	return mp[make_pair(u,v)] = cnt%10000;
}

int main(){
	cin>>n;
	ll ans = 0;
	for(int i=n;i>=1;i--){
		ans = (ans + dfs(i,n))%10000;
	}
	cout<<ans;
	return 0;
} 

##100%數據 記憶化搜索 + 打表法 在記憶化搜索的基礎上,打表 本地打表的測試代碼
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

//100% 打表法: 本地打表的測試代碼 

int n;
map<pair<int,int>,int > mp;

int dfs(int u,int v){
	if(mp[make_pair(u,v)]) return mp[make_pair(u,v)];
	int d = abs(v-u);
	if(d == 0) return mp[make_pair(u,v)] = 1;
	ll cnt = 1;
	for(int i=1;i<d;i++){
		cnt = (cnt + dfs(i,u))%10000;
	}
	return mp[make_pair(u,v)] = cnt%10000;
}

int main(){
	freopen("9.txt","w",stdout);
	printf("int table[1100] = {0,");
	for(n = 1;n<=1000;n++){
		ll ans = 0;
		for(int i=n;i>=1;i--){
			ans = (ans + dfs(i,n))%10000;
		}
		printf("%d",ans%10000);
		if(n!=1000) printf(",");
	}
	printf("}");
	return 0;
} 

打表后正式上交的代碼

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

//100% 打表上交的代碼 

int n;
int table[1100] = {0,1,2,4,7,14,26,53,106,220,452,946,1967,4128,8638,8144,8068,........篇幅有限見下圖};

int main(){
	cin>>n;
	cout<<table[n];
	return 0;
} 



10.

問題描述
小明要組織一台晚會,總共准備了 n 個節目。然后晚會的時間有限,他只能最終選擇其中的 m 個節目。

這 n 個節目是按照小明設想的順序給定的,順序不能改變。

小明發現,觀眾對於晚上的喜歡程度與前幾個節目的好看程度有非常大的關系,他希望選出的第一個節目盡可能好看,在此前提下希望第二個節目盡可能好看,依次類推。

小明給每個節目定義了一個好看值,請你幫助小明選擇出 m 個節目,滿足他的要求。

輸入格式
輸入的第一行包含兩個整數 n , m ,表示節目的數量和要選擇的數量。

第二行包含 n 個整數,依次為每個節目的好看值。

輸出格式
輸出一行包含 m 個整數,為選出的節目的好看值。

評測用例規模與約定
對於 30% 的評測用例,1<=n<=20;
對於 60% 的評測用例,1<=n<=100;
對於所有評測用例,1<=n<=100000,0<=value<=100000。

60% 枚舉

按題意模擬
1.每次選1個數 i∈1~m
2.當前這個數就是: 上一次選的數的右邊 ~ n-(m-i)的區間內的最大值,這里可以O(n)枚舉,也可以O(longn)優化

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

/*
60%
1.每次選1個數 i∈1~m 
2.當前這個數就是: 上一次選的數的右邊 ~ n-(m-i)的區間內的最大值,這里可以O(n)枚舉,也可以O(longn)優化 
*/ 

const int maxn = 1e5+100;
int n,m;
int a[maxn];
int b[maxn];

int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>a[i];
	int pos = 0;
	for(int i = 1;i<=m;i++){ //選第i個數  
		int maxi = a[pos+1];
		for(int j=pos+1;j<n-(m-i)+1;j++){ //pos+1 ~ n-(m-i)+1可以選擇 
			if(a[j] > maxi){ //選出這個區間內最大的,並更新最大值和所在位置下標 
				maxi = a[j];
				pos = j;
			}
		}
		b[i] = maxi;
	}
	for(int i=1;i<m;i++) cout<<b[i]<<" ";
	cout<<b[m];
	return 0;
} 

100% 線段樹優化查詢

按60%的思路中的查詢可以用線段樹優化,用線段樹查詢區間最大值,並記錄結點的位置下標 ,時間復雜度O(nlongn)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

/*
100% 開一個線段樹維護區間最大值 並記錄結點的位置下標 
1.每次選1個數 i∈1~m 
2.當前這個數就是: 上一次選的數的右邊 ~ n-(m-i)的區間內的最大值,可以O(longn)優化 
*/ 

const int maxn = 1e5+100;
int n,m;
int a[maxn];
int b[maxn];

struct node{
	int pos;
	ll maxv;
}tree[maxn*4]; 

void pushup(int o){
	if(tree[o<<1].maxv > tree[o<<1|1].maxv){
		tree[o].maxv = tree[o<<1].maxv;
		tree[o].pos = tree[o<<1].pos;
	}else{
		tree[o].maxv = tree[o<<1|1].maxv;
		tree[o].pos = tree[o<<1|1].pos;
	}
}

void build(int o,int l,int r){
	//初始化結點的標記 
	tree[o].maxv = 0;
	//葉子結點 
	if(l == r){
		tree[o].pos = l;
		tree[o].maxv = a[l];
		return;
	}
	int mid = (l+r)>>1;
	build(o<<1,l,mid);
	build(o<<1|1,mid+1,r);
	pushup(o);
}

void update(int o,int l,int r,int pos,int v){
	if(l == r){ //完全包含該l~r區間 
		tree[o].maxv += v;
		return;
	}
	int mid = (l+r)>>1;
	if(pos <= mid) update(o<<1,l,mid,pos,v);
	else update(o<<1|1,mid+1,r,pos,v);
	pushup(o);
}

pair<int,ll> querymax(int o,int l,int r,int ql,int qr){
	if(ql <= l && r <= qr){ //完全包含 直接return 
		return make_pair(tree[o].pos,tree[o].maxv);
	}
	int mid = (l+r)>>1;
	//查詢出區間最大的max 
	pair<int,ll> temp,u,v; 
	if(ql<=mid) {  
		u = querymax(o<<1,l,mid,ql,qr);
		temp = u;
	}
	if(qr>mid) {
		v = querymax(o<<1|1,mid+1,r,ql,qr);
		if(v.second > temp.second) temp = v;
	}
	return temp;
}

int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>a[i];
	build(1,1,n);
	int pos = 0;
	for(int i = 1;i<=m;i++){ //選第i個數  
		int maxi = a[pos+1];
		//查詢pos+1~(n-(m-i) 閉區間的最大值 
		pair<int,ll> u = querymax(1,1,n,pos+1,n-(m-i));
		pos = u.first; //第i個數選了pos位置 
		maxi = u.second; //第i個數選了maxi這個值 
		b[i] = maxi;
	}
	for(int i=1;i<m;i++) cout<<b[i]<<" ";
	cout<<b[m];
	return 0;
} 
/*
5 3
3 1 2 5 4
*/

不保證每個點的正確性...思路僅供參考...


免責聲明!

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



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