题意: 给定区间 l r ,询问 al%a(l+1)%a[l+2]......a[r] 的值, 1e5个数
很显然一个数只有mod一个小于等于他的数这个数 才会变化,如果我们可以从一个位置,直接跳到刚小于等于这个位置上的数的下一个位置,那么我们就可以跳着mod下去了
我们要是可以记录一个pos数组,pos[i] 表示刚小于等于i位置上的数的下一个位置就好了
当时就是不知道怎么求这个位置。后来看了题解明白了。
刚比i位置上的数略小的位置如果不是i+1 位置, 下一个可能的就是 pos[i+1],这个位置,比如 2 3 4 1
这样就可以大约n*log(n)求出pos 数组。 剩下的就是用pos数组跳跳,,求解。
#include<bits/stdc++.h>
using namespace std;
int n,m;
int pos[100010];
int a[100010];
void getl()
{
pos[n]=-1;
for(int i = n-1; i>=1; i--)
{
int p = i+1;
while(1)
{
if(a[p]<a[i])
{
pos[i]=p;
break;
}
if(p==-1)
{
pos[i]= -1;
break;
}
p=pos[p];
}
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i= 1; i<=n; i++)
{
scanf("%d",&a[i]);
}
scanf("%d",&m);
getl();
for(int i = 1; i<=m; i++)
{
int x,y;
scanf("%d%d",&x,&y);
int ans = a[x];
for(int j = pos[x];; j = pos[j])
{
if(j==-1||j>y)break;
ans = ans%a[j];
}
printf("%d\n",ans);
}
}
return 0;
}