1. 程式人生 > >bzoj 1264 基因匹配

bzoj 1264 基因匹配

Written with StackEdit.

Description

卡卡昨天晚上做夢夢見他和可可來到了另外一個星球,這個星球上生物的\(DNA\)序列由無數種鹼基排列而成(地球上只有\(4\)種),而更奇怪的是,組成\(DNA\)序列的每一種鹼基在該序列中正好出現\(5\)次!這樣如果一個\(DNA\)序列有\(N\)種不同的鹼基構成,那麼它的長度一定是\(5N\)

任務:編寫一個程式:

  • 從輸入檔案中讀入兩個等長的\(DNA\)序列;
  • 計算它們的最長公共子序列長度;
  • 向輸出檔案列印你得到的結果。

Input

輸入檔案中第一行有一個整數\(N\),表示這個星球上某種生物使用了N種不同的鹼基,以後將它們編號為\(1…N\)

的整數。

以下還有兩行,每行描述一個\(DNA\)序列:包含\(5N\)\(1…N\)的整數,且每一個整數在對應的序列中正好出現\(5\)次。

Output

輸出檔案中只有一個整數,即兩個\(DNA\)序列的最長公共子序列長度。

Sample Input

2
1 1 2 2 1 1 2 1 2 2
1 2 2 2 1 1 2 2 1 1

Sample Output

7

HINT

[資料約束和評分方法]

\(60\%\)的測試資料中:\(1<=N <= 1000.\)
\(100\%\)的測試資料中:\(1<=N <= 20000.\)

Solution

  • 樸素的\(O(n^2)dp\)
    只能解決\(60\%\)的部分.
  • 注意到一個關鍵性質,每個數在每個序列中都恰好出現\(5\)次.
  • 類似於給兩個排列求\(LCS\),我們可以記錄下每個數字在第一個序列\(a\)中從前往後的\(5\)個位置.
  • 再處理第二個序列\(b\),此時我們處理當前數\(b[i]\)在第一個序列中每個出現的位置\(pos\).有\(a[pos]=b[i].\)
  • 那麼根據樸素\(dp\)的思路,定義\(f[i]\)為只用\(a\)序列的前\(i\)個數的\(LCS\)長度.
  • 此時就可以完成更新\(f[pos]=max(f[1\)~\(pos-1])+1\).利用樹狀陣列維護最大值進行優化.
  • 特別注意:每個\(b[i]\)
    對應了\(5\)\(pos\),而我們處理它們的時候應該從後往前倒序處理,否則先更新的會對後面的造成影響,破壞無後效性(類似01揹包).
#include<bits/stdc++.h>
#define lowbit(x) x&(-x)
using namespace std;
typedef long long LoveLive;
inline int read()
{
    int out=0,fh=1;
    char jp=getchar();
    while ((jp>'9'||jp<'0')&&jp!='-')
        jp=getchar();
    if (jp=='-')
        {
            fh=-1;
            jp=getchar();
        }
    while (jp>='0'&&jp<='9')
        {
            out=out*10+jp-'0';
            jp=getchar();
        }
    return out*fh;
}
const int MAXN=2e5+10;
int ta[MAXN];
int va[MAXN][10];
int bit[MAXN];
int n;
inline void upd(int x,int c)
{
    for(;x<=n;x+=lowbit(x))
        bit[x]=max(bit[x],c);
}
inline int query(int x)
{
    int res=0;
    for(;x;x-=lowbit(x))
        res=max(res,bit[x]);
    return res;
}
int main()
{
    n=read();
    n*=5;
    for(int i=1;i<=n;++i)
        {
            int t=read();
            va[t][++ta[t]]=i;
        }
    for(int i=1;i<=n;++i)
        {
            int t=read();
            for(int j=5;j>=1;--j)//值得細細斟酌
                {
                    int pos=va[t][j];
                    int mx=query(pos-1)+1;
                    upd(pos,mx);
                }
        }
    int ans=query(n);
    printf("%d\n",ans);
    return 0;
}