蓝桥杯国赛游园安排
Posted iuk11
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了蓝桥杯国赛游园安排相关的知识,希望对你有一定的参考价值。
最长上升子序列 LIS 优化 二分与贪心 单调队列
数据范围 1e6,如果用普通的LIS会超时。
现在介绍优化版本:在单调队列中,保证所有字符串按照字典序单增。首先对题目进行字符串处理,按照顺序依次入队。
入队满足两个条件:
- 当前元素比队尾元素大,直接入队;
- 当前元素比队尾元素小,二分找到第一个大于等于该元素的元素,替换它。
最终的队列长度一定是该序列的最长子序列长度。(结论1)
在每一次入队操作时,同时更新len序列(表示以第i个元素结尾的序列的最长子序列的长度):
- 当前元素比队尾元素大,长度为队列长度;
- 当前元素比队尾元素小,二分找到第一个大于等于该元素的下标,长度为下标+1(当且仅当下标从0开始)。
在处理完这些操作后,我们得到了 len序列(回溯用)
以及 最终的 单调队列(没啥用)
。
因为题目要求输出最长子序列的每个元素,所以根据长度序列进行回溯,找到每个元素。
设最长子序列长度为 m
,有 m=q.size()
,见结论1.
从后往前判断以每个元素结尾,能得到的最长子序列长度,如果正好为当前m
的值,记录一下当前元素为最长子序列中的元素。然后m--
(因为已经又确定了一个元素)。直到m=0
找完所有最长子序列中的元素。
倒序找,要倒序输出,越先找到的元素字典序越大,从小到大输出结果。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+100;
int main()
string s;
cin>>s;
vector<string> str;
string tem;
s+="A";
str.push_back("*");
tem+=s[0];
for(int i=1;i<s.size();i++)
if(s[i]>='A'&&s[i]<='Z')
str.push_back(tem);
tem="";
tem+=s[i];
else
tem+=s[i];
vector<string> q;
vector<int> len;
q.push_back(str[1]);
len.push_back(1);
for(int i=2;i<str.size();i++)
if(str[i]>q.back())
q.push_back(str[i]);
len.push_back(q.size());
else
int l=0,r=q.size()-1;
while(l<r)
int mid=(l+r)>>1;
if(q[mid]>=str[i])
r=mid;
else
l=mid+1;
//int l=lower_bound(q.begin(),q.end(),str[i])-q.begin();
q[l]=str[i];
len.push_back(l+1);
vector<string> res;
for(int i=str.size()-1,m=q.size();m>0;i--)
if(len[i]==m)
res.push_back(str[i+1]);
m--;
for(int i=res.size()-1;i>=0;i--) cout<<res[i];
return 0;
以上是关于蓝桥杯国赛游园安排的主要内容,如果未能解决你的问题,请参考以下文章