Python super() 函式
阿新 • • 發佈:2020-07-26
問題描述
給出一個序列,計算這個序列的遞增子序列的最大長度.
解法
用一個數組dp
記錄到每個數的最長的遞增子列,用一個數組記錄數列,dp[j]
表示已第j
個元素結尾的最長的遞增子列的長度,max_len
表示比第i
個元素小的最長的遞增子列的長度,當以當前元素為結尾的最長遞增子列比那個max_len
大並且當前元素比i
小時,更新max_len
,最後dp[i]
的值就是這個max_len+1
,沒經過內層一輪迴圈更新全域性的最優解,於是得到下面的程式:
void LCS(int n){ memset(dp, 0, sizeof(dp)); memset(heights, 0, sizeof(heights)); for (int i = 1; i <= n; i++) { scanf("%lld", &heights[i]); } dp[1] = 1; ll ans = 0ll; for (int i = 2; i <= n; i++) { int max_len = 0; // for(int j = 1; j <= n; j++) { // printf("%lld ", dp[j]); // } // printf("\n"); for (int j = 1; j <= i; j++) { if( dp[j] > max_len && heights[j] < heights[i]){ max_len = dp[j]; } } dp[i] = max_len + 1; if (ans < dp[i]) ans = dp[i]; } // for(int j = 1; j <= n; j++) { // printf("%lld ", dp[j]); // } // printf("\n"); printf("%lld\n", ans); }
除了這種利用DP來解決的方法,還有一種基於序列本身的特徵的方法,藉助於一個數組d
計算當前LIS
的長度.初始時設定d[0]=heights[1]
,然後開始迭代處理heights
中的每一個數:
- 如果
heights[i]>d[cnt-1]
,那麼d[cnt++]=heights[i]
,也就是說如果當前的高度比d
中最後一個還高,那麼這個應該為LIS
貢獻一個長度; - 如果
heights[i]>d[cnt-1]
不成立,那麼從d
中找到第一個比這個heights[i]
大的位置,然後將這個位置的數替換為heights[i]
.有兩個原因,第一個這個不會影響中的LIS
的長度;其次,heights
LIS
,這樣替換掉d
中第一個比heights[i]
給更小的數字留下機會,heights[i]
可能在LIS
中,被替換的數字更有可能不在LIS
中.
ll d[N]; void lis(int n){ memset(d, 0, sizeof(d)); memset(heights, 0, sizeof(heights)); for(int i=1; i<= n; i++){ scanf("%lld", &heights[i]); } d[0] = heights[1]; int len = 1; for (int i = 2; i <= n; i++){ if( heights[i] > d[len-1]) d[len++] = heights[i]; else{ int t = lower_bound(d, d + len, heights[i])-d; d[t] = heights[i]; } } printf("%d\n", len); }
題目連結
題目概述
有一種反導系統,第一發導彈可以攔截任意高度的導彈,但是後面的每一發都不能超過前面一發發射的高度,現在給出一些地方發射的導彈高度的序列,計算需要的最少的攔截系統的數量.
想法
可以直接用貪心來模擬計算,對於地方發來的導彈,首先從已經部署的翻到系統中找一找有沒有可攔截高度比這個大的,如果有那麼找可攔截的最小的,更高的留給後面高度更高的導彈,如果沒有,那麼需要額外部署一套反導系統.沒進行一次攔截,要更新翻到系統可以攔截的最高高度.可以得到下面這個程式
void solve(int n){
int cnt = 0;
fill(ans, ans + N, INT_MAX);
for(int i = 0; i < n; ++i){
int t;
scanf("%d", &t);
int choice = cnt;
for (int j = 0; j <= cnt; ++j){
// printf("choice=%d,ans[choice]=%lld,cnt=%d,t=%d,j=%d,ans[j]=%lld\n", choice,ans[choice], cnt, t, j, ans[j]);
if( ans[j] >= t && ans[j] <= ans[choice]){
choice = j;
}
}
// printf("%d ", choice);
ans[choice] = t;
if(choice == cnt){
++cnt;
}
}
printf("%d\n", cnt);
}
如果把每個翻到系統攔截的導彈高度單獨拎出來看的話,會發現每個攔截系統攔截的導彈高度序列恰好是一個單調遞減的序列.假設現在有兩個反導系統攔截得到的序列X,Y,對於Y
中至少有一個高度大於X
中的某個高度,從每一個攔截系統中拿出一個數,可以構成一個單調遞增的序列,攔截系統的數量就是這個序列的長度.
程式碼
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 300005;
ll ans[N];
void solve(int n){
int cnt = 0;
fill(ans, ans + N, INT_MAX);
for(int i = 0; i < n; ++i){
int t;
scanf("%d", &t);
int choice = cnt;
for (int j = 0; j <= cnt; ++j){
// printf("choice=%d,ans[choice]=%lld,cnt=%d,t=%d,j=%d,ans[j]=%lld\n", choice,ans[choice], cnt, t, j, ans[j]);
if( ans[j] >= t && ans[j] <= ans[choice]){
choice = j;
}
}
// printf("%d ", choice);
ans[choice] = t;
if(choice == cnt){
++cnt;
}
}
printf("%d\n", cnt);
}
ll dp[N];
ll heights[N];
void LCS(int n){
memset(dp, 0, sizeof(dp));
memset(heights, 0, sizeof(heights));
for (int i = 1; i <= n; i++) {
scanf("%lld", &heights[i]);
}
dp[1] = 1;
ll ans = 0ll;
for (int i = 2; i <= n; i++) {
int max_len = 0;
// for(int j = 1; j <= n; j++) {
// printf("%lld ", dp[j]);
// }
// printf("\n");
for (int j = 1; j <= i; j++) {
if( dp[j] > max_len && heights[j] < heights[i]){
max_len = dp[j];
}
}
dp[i] = max_len + 1;
if (ans < dp[i])
ans = dp[i];
}
// for(int j = 1; j <= n; j++) {
// printf("%lld ", dp[j]);
// }
// printf("\n");
printf("%lld\n", ans);
}
ll d[N];
void lis(int n){
memset(d, 0, sizeof(d));
memset(heights, 0, sizeof(heights));
for(int i=1; i<= n; i++){
scanf("%lld", &heights[i]);
}
d[0] = heights[1];
int len = 1;
for (int i = 2; i <= n; i++){
if( heights[i] > d[len-1])
d[len++] = heights[i];
else{
int t = lower_bound(d, d + len, heights[i])-d;
d[t] = heights[i];
}
}
printf("%d\n", len);
}
int main(int argc, const char** argv) {
int n;
while(~scanf("%d", &n)){
// solve(n);
// LCS(n);
lis(n);
}
return 0;
}