题意
给出两个长度为n的排列a, b(含n个数字,1~n每个数字只出现一次)。假设p,q分别为a,b的子序列,长度相同,且q中每个数字均是p中的倍数。( 1 ≤ n ≤ 2 e 5 1 \leq n \leq 2e5 1≤n≤2e5)
思路
- 将a,b中所有有倍数关系的数子的下标用pair存起来(大约有 N l n N NlnN NlnN )。然后对第一维按升序排列,第一维相同时,第二维按降序排列。此时,问题已经转化为,求pair的第二维中最长的严格上升子序列。
- 由于数据范围较大,只能用贪心+二分的方式求最长上升子序列。
- 同时注意数组越界,调和级数求和为 N l n N NlnN NlnN的级别。 l n ( 2 e 5 ) ≈ 13 ln(2e5) ≈ 13 ln(2e5)≈13所以数组最小要开 2 e 5 × 13 ≈ 3 e 6 2e5 \times 13 ≈ 3e6 2e5×13≈3e6
- 算法时间复杂度: N l o g 2 N Nlog^2N Nlog2N
const int N = 2e5 + 7, M = 3e6 + 7;
int a[N], b[N];
pii s[M];
bool cmp(pii a, pii b)
{
if (a.ft == b.ft) return a.sd > b.sd;
return a.ft < b.ft;
}
int main()
{
IOS;
int n; cin >> n;
for (int i = 1, x; i <= n; i++)
cin >> x, a[x] = i;
for (int i = 1, x; i <= n; i++)
cin >> x, b[x] = i;
int k = 0;
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j += i)
s[k++] = { a[i], b[j] };
sort(s, s + k, cmp);
int ans = 0;
vector<int>v;
for (int i = 0; i < k; i++)
{
if (v.empty() || s[i].sd > v.back())
v.push_back(s[i].sd);
else
{
int idx = lower_bound(all(v), s[i].sd) - v.begin();
v[idx] = s[i].sd;
}
}
cout << sz(v) << endl;
return 0;
}