bzoj 1264 基因匹配
阿新 • • 發佈:2018-12-05
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\)
- 注意到一個關鍵性質,每個數在每個序列中都恰好出現\(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]\)
#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;
}