【CF1422F】Boring Queries 分块预处理+强制在线
George_Plover · · 题解
看了一下题解区的大佬们,无一例外的全部上了可持久化线段树,实在佩服。
鄙人不才,虽然早就做过了 HH的项链 这道题,但是想题的时候还是没有自然的去想可持久化线段树的写法。
这里提供一个分块预处理的做法。总复杂度
题意描述:
给出
题目分析:
-
首先考虑到 lcm 非常大,必须在计算中取模,因此不能够直接的用区间求 lcm 的算法解决。所以考虑答案是质数幂次之积的形式,即
ans=p_1^{k_1}p_2^{k_2}\dots p_s^{k_s} 。 -
观察性质,
a_i 范围很小,因此,对于\sqrt{2\times 10^5} ≈ 447 以内的质因子,幂次才可能大于1 ,其余的质因子的幂次要么是1 ,要么是0 。因此我们考虑分段处理。
做法:
第一部分
考虑处理
因此,我们可以用一个 pre[222][n],其中pre[][i]存下的是每个质因子的某个幂次在 pre[][r]>=l 幂次,这就是这个质因子对答案的贡献。这样我们就可以
第二部分
考虑第二部分,我们先把原来的
每 itv[L][R] 表示从第 itv[][] 数组得到其贡献,然后再把这个区间向左右拓展,因此不满整块的
于是把上面两个过程结合起来,就可以以
代码:
#include <map>
#include <cmath>
#include <cstdio>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define MOD 1000000007
#define MAXN 220000
#define MAXC 230
#define LSQRT 87
#define BSIZE 350
using namespace std;
int n,m,a[MAXN];
int Div[MAXN],prime[MAXN],cnt;
int range[MAXN];
int base[MAXN];
int power[LSQRT][20];
int pre[MAXC][MAXN];
int loc[MAXN],lm[MAXN],rm[MAXN];
int itv[BSIZE][BSIZE];
bool vis[MAXN];
void get_p()
{
for(int i=2;i<MAXN;i++)
{
if(!Div[i])
{
prime[++cnt]=i;
Div[i]=i;
}
for(int j=1;j<=cnt&&prime[j]*i<MAXN;j++)
{
Div[prime[j]*i]=prime[j];
if(prime[j]==Div[i])
break;
}
}
}
void prepare_first()
{
int sum=0;
for(int i=1;i<LSQRT;i++)
{
range[i]=(log(200000)/log(prime[i]));
base[i]=sum;
sum+=range[i];
}
for(int i=1;i<=n;i++)
{
for(int j=0;j<MAXC;j++)
pre[j][i]=pre[j][i-1];
for(int j=1;j<LSQRT;j++)
{
int cnt = 0;
while(!(a[i]%prime[j]))
{
cnt++;
a[i]/=prime[j];
}
if(cnt)
pre[base[j]+cnt-1][i]=i;
}
}
for(int i=1;i<LSQRT;i++)
{
int tmp=1;
for(int j=1;j<20;j++)
{
tmp=1ll*tmp*prime[i]%MOD;
power[i][j]=tmp;
}
}
}
void prepare_second()
{
for(int i=1;i<=n;i++)
{
lm[i]=loc[a[i]];
loc[a[i]]=i;
}
for(int i=1;i<MAXN;i++)loc[i]=n+1;
for(int i=n;i>=1;i--)
{
rm[i]=loc[a[i]];
loc[a[i]]=i;
}
for(int i=1;i<=n;i+=BSIZE)
{
memset(vis,0,sizeof(vis));
int tmp=1;
for(int j=i;j<=n;j++)
{
if(!vis[a[j]])
{
vis[a[j]]=1;
tmp=1ll*tmp*a[j]%MOD;
}
if( !(j%BSIZE) || j==n)
{
itv[i/BSIZE][(j-1)/BSIZE]=tmp;
}
}
}
}
int main()
{
get_p();
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
prepare_first();
prepare_second();
scanf("%d",&m);
int lst=0;
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
x=(lst+x)%n+1;
y=(lst+y)%n+1;
if(x>y)
swap(x,y);
lst=1;
for(int i=1;i<LSQRT;i++)
{
for(int j=base[i]+range[i]-1;j>=base[i];j--)
{
if(pre[j][y]>=x)
{
lst=1ll*lst*power[i][j-base[i]+1]%MOD;
break;
}
}
}
if(y-x+1 <= 2*BSIZE)
{
for(int i=x;i<=y;i++)
if(lm[i]<x)
lst=1ll*lst*a[i]%MOD;
}
else
{
int L=(x-1)/BSIZE + 1,R=(y-1)/BSIZE - 1;
lst=1ll*lst*itv[L][R]%MOD;
for(int i=x;i<=L*BSIZE;i++)
if(rm[i]>(R+1)*BSIZE)
lst=1ll*lst*a[i]%MOD;
for(int i=(R+1)*BSIZE+1;i<=y;i++)
if(lm[i]<x)
lst=1ll*lst*a[i]%MOD;
}
printf("%d\n",lst);
}
return 0;
}