您的位置:首页 > 运维架构

CodeForces Manthan 2011 D. Optical Experiment(动态规划)

2013-05-10 22:44 316 查看

题目大意

这题建议大家先看看原题是怎么描述的,在看看我讲的中文题面,本来我打算直接翻译的,但是考虑到文字太多,还是算了

原题链接:D. Optical Experiment

我描述的中文题意:

题意化简之后就是一个矩形,上下两边各有 n(1≤n≤106) 个点,每个上边的点只会和下边的一个点相连,构成一条线段,那么就有了 n 条线段,现在问:这 n 条线段中,最多有多少线段,他们两两相交?输出这个最大的线段数量

做法分析

把矩形上边的点依次重新编号(从小到大),下边对应线段的点编上相同的号

假设 m 条线段两两相交,那么这 m 条线段在上边的编号必然是递增的,在下边的编号必然是递减的

那么问题转化成了在下边求一个最长下降的子序列,必须用 nlogn 的做法

PS:这题的关键是题意的转化以及对线段的重新编号,好题!出题人隐藏的太深!

参考代码

Optical Experiment

#include <cstring>
#include <cstdio>
#include <iostream>
#include <map>

using namespace std;

const int N=1000006;

map <int, int> ihash;
int n, s
, t
, f
, len
, ans;

int main()
{
scanf("%d", &n);
for(int i=0; i<n; i++)
{
scanf("%d", &s[i]);
ihash.insert(make_pair(s[i], i+1));
}
int ans=0;
for(int i=0; i<n; i++)
{
scanf("%d", &t[i]);
t[i]=ihash[t[i]];
}
memset(f, 0, sizeof f);
f[0]=1, len[1]=t[0], ans=1;
for(int i=1; i<n; i++)
{
int Min=len[f[i-1]];
if(t[i]<Min) len[++ans]=t[i], f[i]=f[i-1]+1;
else
{
int L=1, R=ans;
while(L<R)
{
int mid=(L+R)>>1;
if(len[mid]<t[i]) R=mid;
else L=mid+1;
}
if(len[L]<t[i]) L--;
L++;
len[L]=t[i];
f[i]=f[i-1];
}
}
printf("%d\n", ans);
return 0;
}


题目链接 & AC通道

CodeForces Manthan 2011 D. Optical Experiment
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: