題面
https://www.lydsy.com/JudgeOnline/problem.php?id=4990
分析
首先可以看出一個簡單的DP
dp[i][j]表示序列a前i個與序列b前j個連線數量
這樣DP的時間複雜度爲
發現該方程除了轉移的判斷條件之外和LCS並無什麼不同,因此可考慮LCS的優化方法
提示:閱讀下面內容前,請先確保自己掌握一般情況下LCS轉LIS的過程,以及LIS的算法
考慮LCS轉LIS,原本的方法是記錄a[i]中每個值的位置pos,將b[i]轉化爲pos[b[i]]
既然都可杯看做“相等”
則我們對於每個b[i]±j (0<=j<=4),將pos[b[i]±j]加入數組c,求c的LIS即爲答案
但注意到每個點只能連一條邊,也就是對於每個b[i],9個b[i]±j中只能選一個加入LIS
所以將9個一組從大到小排序,再拼起來,這樣每組數中至多有一個數被選進LIS,(若選兩個,則c[i]>c[i+1],矛盾)
時間複雜度
代碼
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define maxn 100005
using namespace std;
int n;
int a[maxn],b[maxn];
int pos[maxn];
vector<int>tmp;
vector<int>c;
int s[maxn*9];
int m;
int cmp(int x,int y) {
return x>y;
}
int solve() {
for(int i=1;i<=n;i++){
tmp.clear();
for(int j=0;j<=4;j++){
if(b[i]+j<=n) tmp.push_back(pos[b[i]+j]);
if(b[i]-j>=1) tmp.push_back(pos[b[i]-j]);
}
sort(tmp.begin(),tmp.end(),cmp);
int t=tmp.size();
for(int j=0;j<t;j++){
c.push_back(tmp[j]);
}
}
int m=c.size();
// for(int i=0;i<m;i++) printf("%d ",c[i]);
// printf("\n");
int top=0;
for(int i=0; i<m; i++) {
if(c[i]>s[top]) {
s[++top]=c[i];
} else {
int tmp=lower_bound(s+1,s+1+top,c[i])-s;
s[tmp]=c[i];
}
}
return top;
}
int main() {
scanf("%d",&n);
for(int i=1; i<=n; i++) {
scanf("%d",&a[i]);
pos[a[i]]=i;
}
for(int i=1; i<=n; i++) {
scanf("%d",&b[i]);
}
printf("%d\n",solve());
}