CF474F Ant colony
简略题意
给定一个 个元素的序列 ,并且给定 次询问,每次询问给定区间 ,设 ,询问 ,即求 。
解法
给一个离线解法。
第一步,,考虑先离散化。
首先考虑 ,明显可以线段树维护,维护的复杂度 ,因为计算 的复杂度是 的, 是值域。
维护完之后明显要求 在 中出现的次数,大家都是什么 ST 表或者其他解法,但是出现次数这个问题可以莫队解决。
总结起来,我们对每次询问计算 ,然后莫队维护区间 中这个 出现次数。
接着分析复杂度:
线段树维护的复杂度是 ,而莫队复杂度 ,所以总复杂度 (应该没错吧,因为 ,所以我们算复杂度时假设 同阶,因为不知道 和 谁大,所以我们相加。如果有错请指出)。
复杂度好像很大,但是最慢的点也就三百多毫秒,轻松通过。
不得不说有紫题的难度。
代码:
#pragma GCC optimize(2)
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <utility>
#include <unordered_map>
using namespace std;
const int N = 1e5 + 5;
inline int gcd(int a, int b)
{
return (b == 0 ? a : gcd(b, a % b));
}
int ans[N], a[N], b[N], n, m, len, cntk[N], real[N];
unordered_map<int, bool> mp;
struct Node
{
int l, r, gcdn;
}tree[N << 2];
inline void push_up(int u)
{
tree[u].gcdn = gcd(tree[u << 1].gcdn, tree[u << 1 | 1].gcdn);
}
inline void build(int u, int l, int r)
{
tree[u] = { l, r };
if (l == r) tree[u].gcdn = real[a[r]];
else
{
int mid = (l + r) >> 1;
build(u << 1, l, mid);
build(u << 1 | 1, mid + 1, r);
push_up(u);
}
}
inline int query(int u, int l, int r)
{
if (tree[u].l >= l && tree[u].r <= r) return tree[u].gcdn;
int mid = (tree[u].l + tree[u].r) >> 1;
int k = 0;
if (l <= mid)
{
k = query(u << 1, l, r);
}
if (r > mid)
{
k = gcd(k, query(u << 1 | 1, l, r));
}
return k;
}
struct Nodeq
{
int rid, l, r, gcdn;
bool operator<(const Nodeq& g) const
{
int i = l / len, j = g.l / len;
return (i ^ j ? i < j : i & 1 ? r < g.r : r > g.r);
}
}q[N];
inline void add(int x)
{
++cntk[a[x]];
}
inline void del(int x)
{
--cntk[a[x]];
}
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; ++i)
{
scanf("%d", &a[i]);
b[i] = a[i];
mp[a[i]] = true;
}
sort(b + 1, b + n + 1);
int place = unique(b + 1, b + n + 1) - b - 1;
for (register int i = 1; i <= n; ++i)
{
int k = a[i];
a[i] = lower_bound(b + 1, b + place + 1, a[i]) - b + 1;
real[a[i]] = k;
}
build(1, 1, n);
scanf("%d", &m);
for (register int i = 1; i <= m; ++i)
{
register int l, r;
scanf("%d %d", &l, &r);
int qp = query(1, l, r);
q[i] = { i, l, r, qp };
}
len = sqrt(m);
sort(q + 1, q + m + 1);
register int nl = 1, nr = 0;
for (register int i = 1; i <= m; ++i)
{
int l = q[i].l, r = q[i].r;
while (nl < l) del(nl++);
while (nl > l) add(--nl);
while (nr < r) add(++nr);
while (nr > r) del(nr--);
if (!mp[q[i].gcdn]) ans[q[i].rid] = r - l + 1;
else ans[q[i].rid] = (r - l + 1) - cntk[lower_bound(b + 1, b + place + 1, q[i].gcdn) - b + 1];
}
for (register int i = 1; i <= m; ++i) printf("%d\n", ans[i]);
return 0;
}