题意:给你一个长度为n的数组,现在有q次询问,每次询问给你l, r, 求a[l]%a[l+1]%a[l+2]...%a[r], (n <= 1e5, q多大没给。。。)
思路:因为取模一个比自己大的数是没用的,所以我们每次只需要找下一个比当前结果小的就行,这样就可以RMQ预
处理区间最值,然后二分查找下一个位置了。。。有个知识,一个数x,最多只能被取模logx次。所以这个解法的时间
复杂度是可以保证的
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
int a[maxn], n, q;
int dpMin[maxn][20], mm[maxn];
void initRMQ()
{
mm[0] = -1;
for(int i = 1; i < maxn; i++)
mm[i] = ((i&(i-1))==0) ? mm[i-1]+1 : mm[i-1];
for(int i = 1; i <= n; i++)
dpMin[i][0] = a[i];
for(int j = 1; j <= mm[n]; j++)
for(int i = 1; i+(1<<j)-1 <= n; i++)
dpMin[i][j] = min(dpMin[i][j-1], dpMin[i+(1<<(j-1))][j-1]);
}
int RMQ(int l, int r)
{
int k = mm[r-l+1];
return min(dpMin[l][k], dpMin[r-(1<<k)+1][k]);
}
int main(void)
{
int _;
cin >> _;
while(_--)
{
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%d", &a[i]);
initRMQ();
scanf("%d", &q);
while(q--)
{
int l, r;
scanf("%d%d", &l, &r);
int ans = a[l];
if(l == r)
{
printf("%d\n", ans);
continue;
}
l++;
while(l <= r)
{
int L = l, R = r;
int pos = -1;
while(L <= R)
{
int mid = (L+R)/2;
if(RMQ(L, mid) <= ans) pos = mid, R = mid-1;
else L = mid+1;
}
if(pos != -1)
ans %= a[pos], l = pos+1;
else
break;
}
printf("%d\n", ans);
}
}
return 0;
}