题意:给定$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(); }