1. 程式人生 > 其它 >2021.10.11 提高組模擬

2021.10.11 提高組模擬

總的來說考得一般般……100+10+85+10,就那樣。

T1 a

題意:

給定一個長度為 \(N(N\le 10^7)\) 的僅包含小寫字母的字串。請你求出其字典序最大的子序列。

解法

題解是什麼不重要,反正我的玄學方法能過就行了。我的做法是先把所有的字元z找出來輸出,再找y,依次下去,然而這個帶常數的做法目前為止還是最優解

#include<cstdio>
//#define zczc
inline void read(int &wh){
    wh=0;int f=1;char w=getchar();
    while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
    while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar(); }
    wh*=f;return;
}

int m,sum[30];
char w;

signed main(){
	
	#ifdef zczc
	freopen("in.txt","r",stdin);
	#endif
	
	read(m);
	w=getchar();
	while(w<'a'||w>'z')w=getchar();
	sum[w-'a']++;
	for(int i=2;i<=m;i++){
		w=getchar();
		sum[w-'a']++;
		for(int j=w-'a'-1;j>=0;j--)sum[j]=0;
	}
	for(int i=25;i>=0;i--){
		while(sum[i]--)putchar(i+'a');
	}
	
	return 0;
}

T2 b

題意

給定一個長度為 \(N(N\le 5\times 10^6)\) 的序列。刪除其中的一個元素需要花費的代價是其本身乘上與其相鄰的
元素的乘積。請你求出將該序列刪空的最小代價。

解法

首先我想到的是什麼區間DP,但是沒寫出來;後來想到一個似乎是絕妙的優化,那就是每次刪除只會刪除左端點或者右端點,這樣一定是最優的,因為這樣一來,每次的代價就會是兩個數相乘,而不是三個數連乘。

於是考試時打了個奇怪的線性DP,交上去,只有20分,實在不應該。

後來看了解法,發現是因為沒有考慮到一些情況,比如對於序列 1 2 1,它的最優解就是先刪中間再刪兩邊,答案為4 。為什麼會造成這一情況呢,不是因為結論有問題,而是因為那個“兩數乘積小於三數乘積”的結論在這三個數中有1時不再適用。於是用題解的話說,就是以1為分界把原序列割裂成許多小段,對每個小段用上面的結論快速求解。

由資料規模可知,對於每個小段應用 \(O(N)\) 的複雜度求解。

一如既往,萬事勝意