您的位置:首页 > Web前端

bzoj 4990: [Usaco2017 Feb]Why Did the Cow Cross the Road II

2017-08-28 13:44 465 查看
题意:给出两个长度为n的序列a和b,|a[i]-b[j]|<=4算匹配,求最长公共子序列。n<=1000000

n这么大,直接用传统的O(n2)做法肯定是不行的。所以我就学了一个神奇的O(nlogn)算法。

对于b里面的每一个元素,我们找到可以和它匹配的元素在a里面出现的位置,将它们从大到小排序,替代原来在b的位置,然后在新的b里求最长上升子序列,这一步是可以O(nlogn)求出来的。我们来看一个例子(无视原题的匹配条件,这个例子中相等才匹配):

a={1,2,2,5,3}

b={1,2,3}

b中元素在a中位置:

1:1

2:2,3

3:5

排序,放回原来的位置:

新b={1,3,2,5}

对新的b求lis,答案就是3。

从大到小排序是为了不让b中的一个元素匹配两个a中的元素。

代码(用了一大堆vector,所以非常慢。。):

#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#include<iostream>
using namespace std;

int n,pos[1000010];
vector<int>a;

int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
pos[x]=i;
}
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
vector<int>hh;
for(int j=-4;j<=4;j++)
{
if(x+j>0&&x+j<=n)
hh.push_back(pos[x+j]);
}
sort(hh.begin(),hh.end(),greater<int>());/*
for(int i=0;i<hh.size();i++)
printf("%d ",hh[i]);*/
a.insert(a.end(),hh.begin(),hh.end());
}/*
puts("");
for(int i=0;i<a.size();i++)
printf("%d ",a[i]);
puts("");*/
vector<int>s;
int sz=a.size();
for(int i=0;i<sz;i++)
{
vector<int>::iterator it=lower_bound(s.begin(),s.end(),a[i]);
if(it==s.end())
s.push_back(a[i]);
else
*it=a[i];
}
printf("%d",s.size());
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: