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")