1264: [AHOI2006]基因匹配Match(动态规划神题)

1264: [AHOI2006]基因匹配Match

题目:传送门

简要题意:

  给出两个序列。每个序列都由n种不同的数字组成,保证每个序列种每种数字都会出现5次(位置不一定一样),也就是序列长度为5*n啦。

  求这两个序列的最长公共子序列。

题解:

  假的(nlogn)最长公共子序列算法

  本蒟蒻看完题:

    woc!大水题,这不是就是动态规划求最长公共子序列吗~

  看完数据范围...ORZ那么大!!!最长公共子序列的基础算法要(n^2)...完了...不会...瞎搞???

  这么皮,怎么破!

  tkj神犇:so easy~~(orz...%%%)

  好的,%完师兄...

  真正的正解:

  本题的突破口其实就在于每种数只出现5次。

  那么我们可以先把第一个数列种每种数出现的位置用pos[]记录,然后放到第二个数列。

  举个栗子,就拿样例来说:

  第一个:1 1 2 2 1 1 2 1 2 2

  那么pos[1]=1,2,5,6,8       pos[2]=3,4,7,9,10

  然后放回第二个数列:1 2 2 2 1 1 2 2 1 1 

  用一个新的s[]记录新数列,s[]=8 6 5 2 1,10 9 7 4 3, 10 9 7 4 3...(以此类推)

  那么我们只需要求出这个新数列的最长上升子序列就ok啦~(原理十分简单,模拟一下就ok)

  这里还有一个小细节需要注意:不难发现,我们更新新数列的时候每种数字的位置都是按倒序放的,这样就可以避免在第二个数列中的一个位置重复选择(重点)。

  好啦,这样子时间复杂度就为(nlongn)

  但是...是假的...因为要是每种数不止出现五次...那就ORZ吧!

AC代码:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<cmath>
 5 #include<algorithm>
 6 #define qread(x)x=read();
 7 using namespace std;
 8 inline int read()
 9 {
10     int f=1,x=0;char ch;
11     while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
12     while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
13     return f*x;
14 }
15 struct node1
16 {
17     int pos[10],id;
18     node1(){id=0;}
19 }a[21000];
20 struct node2
21 {
22     int pos[10],id;
23     node2(){id=0;}
24 }b[21000];
25 int s[510000];
26 int n,N,len;
27 bool cmp(int n1,int n2)
28 {
29     return n1>n2;
30 }
31 int f[510000];//表示长度为i的最长上升子序列的末尾(最小) 
32 int erfen(int x)
33 {
34     int l=1,r=len,ans=1;
35     while(l<=r)
36     {
37         int mid=(l+r)/2;
38         if(f[mid]>=s[x])
39         {
40             ans=mid;
41             r=mid-1;
42         }
43         else l=mid+1;
44     }
45     return ans;
46 }
47 int main()
48 {
49     qread(n);
50     for(int i=1;i<=n*5;i++)
51     {
52         int x;qread(x);
53         a[x].id++;
54         a[x].pos[a[x].id]=i;
55     }
56     for(int i=1;i<=n;i++)sort(a[i].pos+1,a[i].pos+5+1);
57     for(int i=1;i<=n*5;i++)
58     {
59         int x;qread(x);
60         int k;
61         k=a[x].id;
62         for(int j=i*5-4;j<=i*5;j++)
63         {
64             s[j]=a[x].pos[k];
65             k--;
66         }
67     }
68     N=n*25;
69     f[1]=s[1];len=1;
70     for(int i=2;i<=N;i++)
71     {
72         if(s[i]>f[len])
73             f[++len]=s[i];
74         else
75         {
76             int j=erfen(i);
77             f[j]=s[i];
78         }
79     }
80     printf("%d
",len);
81     return 0;
82 }
原文地址:https://www.cnblogs.com/CHerish_OI/p/8037168.html