Dilworth定理:
最少的下降序列个数就等于整个序列最长上升子序列的长度
大部分答案都是基于这个,但这个数学定理还蛮冷门的,临时遇到肯定不会做,所以再多写了一个暴力解
求最长递减子序列还是用传统dp
同时用一系列队列来模拟排队过程
策略是拿到一个数字看看已有队列能不能放下它
如果有,把它放在队尾数字最小的队列之后
如果没有,则新开一个队列
因为导弹最多一千枚,复杂度倒是没有很夸张
#include <climits>
#include <iostream>
#include <vector>
using namespace std;
int main() {
int n,t,i,j;
cin>>n;
vector<pair<int, int>> dp(n,{1,1});//第一个元素代表最多拦截数量,第二个元素代表组合数
//一个是最多,一个是最优组合
vector<int> nums(n);
int result1=0,result2=0;
// cout<<n<<endl;
dp[0]={1,1};
for(i=0;i<n;++i){
cin>>nums[i];
for(j=0;j<i;++j){
if(nums[i]<=nums[j]){
//延续原有序列
dp[i].first=max(dp[i].first,dp[j].first+1);
}else{
dp[i].second=max(dp[i].second,dp[j].second+1);
}
}
result1=max(result1,dp[i].first);
result2=max(result2,dp[i].second);
// cout<<dp[i].first<<' '<<dp[i].second<<endl;
}
cout<<result1 <<endl<<result2<<endl;
return 0;
}
#include <climits>
#include <iostream>
#include <deque>
using namespace std;
int main() {
int n,t,i,j,result1=0,result2;
cin>>n;
deque<deque<int>> dp; //暴力解法,保存每个导弹
deque<int> nums,dp1(n,1);
int last;
deque<int>* p;
for(i=0;i<n;++i){
cin>>t;
nums.push_back(t);
p=nullptr;
last = INT_MAX;
for(deque<int> &k:dp){
if(k.back()>=t && k.back()<last){
last=k.back();
p=&k;
}
}
if(!p){dp.push_back({t});}else{
p->push_back(t);
}
for(j=0;j<i;++j){
if(nums[j]>=nums[i])dp1[i]=max(dp1[i],dp1[j]+1);
}
result1=max(dp1[i],result1);
}
//print2d(dp);
cout<<result1<<endl<<dp.size()<<endl;
}
// 64 位输出请用 printf("%lld")

京公网安备 11010502036488号