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

 

题目大意

 

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

原题链接:D. Optical Experiment

 

 

我描述的中文题意:

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

 

做法分析

 

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

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

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

 

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

 

参考代码

 

Optical Experiment
 1 #include <cstring>
 2 #include <cstdio>
 3 #include <iostream>
 4 #include <map>
 5 
 6 using namespace std;
 7 
 8 const int N=1000006;
 9 
10 map <int, int> ihash;
11 int n, s[N], t[N], f[N], len[N], ans;
12 
13 int main()
14 {
15     scanf("%d", &n);
16     for(int i=0; i<n; i++)
17     {
18         scanf("%d", &s[i]);
19         ihash.insert(make_pair(s[i], i+1));
20     }
21     int ans=0;
22     for(int i=0; i<n; i++)
23     {
24         scanf("%d", &t[i]);
25         t[i]=ihash[t[i]];
26     }
27     memset(f, 0, sizeof f);
28     f[0]=1, len[1]=t[0], ans=1;
29     for(int i=1; i<n; i++)
30     {
31         int Min=len[f[i-1]];
32         if(t[i]<Min) len[++ans]=t[i], f[i]=f[i-1]+1;
33         else
34         {
35             int L=1, R=ans;
36             while(L<R)
37             {
38                 int mid=(L+R)>>1;
39                 if(len[mid]<t[i]) R=mid;
40                 else L=mid+1;
41             }
42             if(len[L]<t[i]) L--;
43             L++;
44             len[L]=t[i];
45             f[i]=f[i-1];
46         }
47     }
48     printf("%d\n", ans);
49     return 0;
50 }

 

题目链接 &  AC通道

 

CodeForces Manthan 2011 D. Optical Experiment

 

 

 

posted @ 2013-05-10 22:44  jianzhang.zj  阅读(425)  评论(0编辑  收藏  举报