[CF359D] Pair of Numbers - dp
Description
找到序列中最长的区间,满足区间中有一个数 x 可以整除区间内任意数。(ai le 10^6)
Solution
一种暴力的做法:如果一个数可以整除区间内所有数,他一定是这个区间的 min,同时是这个区间的 gcd。所以,一个区间可行,当且仅当这个区间的 gcd=min。二分答案,用 ST 表季胺盐即可
设 li 表示 i 能整除的区间 ([?,i]) 的最小的 ?,ri 同理
求这个东西可以递推,如果 i 能整除 ([?,i]) 那么 i 也能整除 ([l[?],i])
所以我们每次往左边试探一位
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e6 + 5;
int n, a[N], l[N], r[N], ans;
vector<int> av;
signed main()
{
ios::sync_with_stdio(false);
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i];
for (int i = 1; i <= n; i++)
{
l[i] = i;
while (a[l[i] - 1] % a[i] == 0 && l[i] > 1)
l[i] = l[l[i] - 1];
}
for (int i = n; i >= 1; i--)
{
r[i] = i;
while (a[r[i] + 1] % a[i] == 0 && r[i] < n)
r[i] = r[r[i] + 1];
}
for (int i = 1; i <= n; i++)
{
int tans = r[i] - l[i];
if (tans > ans)
{
ans = tans;
av = {l[i]};
}
else if (tans == ans)
{
if (av.size() && l[i] == av.back())
continue;
av.push_back(l[i]);
}
}
cout << av.size() << " " << ans << endl;
for (auto i : av)
cout << i << " ";
}