Description
给定一个长度为 n n n 的数组 a a a。
要求回答 m m m 个询问。
对于每个询问,给出 l , r , k l,r,k l,r,k,求 m a x i = l r { a i % k } max_{i=l}^{r}\left\{ a_i\ \%\ k \right\} maxi=lr{ai % k}。
1 ≤ n , a i , l , r , k ≤ 1 0 5 + 1 1\leq n,a_i,l,r,k \leq 10^5+1 1≤n,ai,l,r,k≤105+1。
Solution
分块,块数 100 100 100。
记 f [ i ] [ j ] f[i][j] f[i][j] 表示第 i i i 块的数 % j \%j %j 的最大值,考虑怎么求 f [ i ] [ j ] f[i][j] f[i][j]。
显然有 a i % j = a i − ⌊ a i j ⌋ × j a_i\%j=a_i-\lfloor\frac{a_i}{j}\rfloor×j ai%j=ai−⌊jai⌋×j。
那么枚举 k k k,在所有满足 ⌊ a i j ⌋ = k \lfloor\frac{a_i}{j}\rfloor=k ⌊jai⌋=k 的 a i a_i ai 中取 a i − k × j a_i-k×j ai−k×j 的最大值。
这相当于找满足 a i < ( k + 1 ) × j a_i<(k+1)×j ai<(k+1)×j 的最大的 a i a_i ai。
对于每块,预处理 b [ x ] b[x] b[x] 表示这一块 ≤ x ≤ x ≤x 的数当中的最大值。
然后枚举 j , k j,k j,k, f [ i ] [ j ] = m a x ( b [ ( k + 1 ) × j − 1 ] − k × j ) f[i][j]=max(b[(k+1)×j-1]-k×j) f[i][j]=max(b[(k+1)×j−1]−k×j)。
假设 n , a i n,a_i n,ai 同阶,那么预处理时间复杂度 O ( 100 n log n ) O(100n\log n) O(100nlogn),常数非常小。
询问复杂度 O ( 1000 m ) O(1000m) O(1000m)。
Code
#include <bits/stdc++.h>
using namespace std;
template <class t>
inline void read(t & res)
{
char ch;
while (ch = getchar(), !isdigit(ch));
res = ch ^ 48;
while (ch = getchar(), isdigit(ch))
res = res * 10 + (ch ^ 48);
}
const int e = 100005, o = 105, m = 100001;
int f[o][e], n, a[e], bl[e], s, br[e], b[e], bel[e], q;
int main()
{
int i, j, k, now = 0, l, r;
read(n); read(q); s = n / 100 + 1;
for (i = 1; i <= n; i++) read(a[i]);;
for (i = 1; i <= n; i = j + 1)
{
bl[++now] = i; br[now] = j = min(n, now * s);
for (k = i; k <= j; k++) bel[k] = now;
}
for (i = 1; i <= now; i++)
{
l = bl[i]; r = br[i];
for (j = 1; j <= m; j++) b[j] = 0;
for (j = l; j <= r; j++) b[a[j]] = a[j];
for (j = 1; j <= m; j++) b[j] = max(b[j], b[j - 1]);
for (j = 1; j <= m; j++)
for (k = 0; k <= m; k += j)
f[i][j] = max(f[i][j], b[min(m, k + j - 1)] - k);
}
while (q--)
{
read(l); read(r); read(k);
int pl = bel[l], pr = bel[r], ans = 0;
if (pl == pr)
{
for (i = l; i <= r; i++) ans = max(ans, a[i] % k);
}
else
{
for (i = pl + 1; i < pr; i++) ans = max(ans, f[i][k]);
for (i = l; i <= br[pl]; i++) ans = max(ans, a[i] % k);
for (i = bl[pr]; i <= r; i++) ans = max(ans, a[i] % k);
}
printf("%d\n", ans);
}
fclose(stdin);
fclose(stdout);
return 0;
}