题意:给定$a_{1\cdots n}$和$p$,多次询问$\prod\limits_{i=l}^ra_i$对$p$取模的值,强制在线,每次询问要求$O(1)$回答
一个微小的黑科技...
静态区间查询,可以想到ST表,但ST表的区间会互相覆盖,不能满足这题的要求,也不能前缀和因为$p$可能不是质数
于是我们有一个类似ST表的技术
设$A_{k,i}=\prod\limits_{j=\left\lfloor\frac i{2^k}\right\rfloor2^k}^ia_j,B_{k,i}=\prod\limits_{j=i}^{\left\lceil\frac{i+1}{2^k}\right\rceil2^k-1}a_j$
$A_{k,i}$表示的是($\leq i$的最大的$2^k$的倍数)到$i$这一段数的乘积,$B_{k,i}$表示的是$i$到($\gt i$的最小的$2^k$的倍数$-1$)这一段数的乘积,这两个都可以$O(n\log_2n)$预处理
对于询问$[l,r]$,如果$l=r$那么答案就是$a_l$,下面讨论$l\lt r$的情况
如果我们可以找到一个$k$,使得$[l+1,r]$中只有一个$2^k$的倍数,那么$B_{k,l}A_{k,r}$就是答案
容易验证一个满足要求的$k$就是$\log_2\left(\text{highbit}(r\text{ xor }l)\right)$,然后这题就做完了...
#include<stdio.h>
typedef long long ll;
void swap(int&a,int&b){a^=b^=a^=b;}
int p;
int mul(int a,int b){return a*(ll)b%p;}
int a[1000010],b[320010],hb[1048577],A[20][1000010],B[20][1000010];
int query(int l,int r){
if(l==r)return a[l]%p;
int k=hb[l^r];
return mul(B[k][l],A[k][r]);
}
int up(int x,int k){
return(x&((1<<k)-1))==0?x>>k:(x>>k)+1;
}
void work(){
int n,q,i,j,l,r,x;
scanf("%d%d%d",&n,&p,&q);
for(i=0;i<n;i++)scanf("%d",a+i);
for(i=0;i<n;i++)A[0][i]=B[0][i]=a[i];
for(j=1;1<<j<n;j++){
for(i=0;i<n;i++)A[j][i]=mul(a[i],i>>j<<j==i?1:A[j][i-1]);
B[j][n]=1;
for(i=n-1;i>=0;i--)B[j][i]=mul(a[i],(up(i+1,j)<<j)-1==i?1:B[j][i+1]);
hb[1<<j]=j;
}
hb[1<<j]=j;
j=1<<j;
for(i=1;i<j;i++){
if(!hb[i])hb[i]=hb[i-1];
}
for(i=0;i<q/64+2;i++)scanf("%d",b+i);
x=0;
for(i=0;i<q;i++){
if((i&63)==0){
l=(b[i>>6]+x)%n;
r=(b[(i>>6)+1]+x)%n;
}else{
l=(l+x)%n;
r=(r+x)%n;
}
if(l>r)swap(l,r);
x=(query(l,r)+1)%p;
}
printf("%d\n",x);
}
int main(){
int T;
scanf("%d",&T);
while(T--)work();
}