题意:
给你n个数和m个查询,然后问你从查询的左端点到右端点依次取模得到的值是多少?
思路: 根据取模的性质,我们可以知道有些数是不用取模的,那么我们主要做的就是如和找到比当前数小的第一个数的位置在哪了,我在网上看到的代码有 就是预处理出比他小的当前的第一个数,时间复杂度大概是 n方,,但是可以过。,这题的正解应该是RMQ预处理出区间最小值,之后二分区间找到第一个比他大的数,时间复杂度是 n*logn*logn。
(还有这套题的输入输出格式真是尼玛丧心病狂,第一次看见有这个 多组输入t组的输入格式)
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#define mes(a) memset(a,0,sizeof(a))
using namespace std;
const int maxn = 110000;
int a[maxn] , dp[maxn][24] , n;
void init()
{
for(int i = 1 ; i<=n ; i++)
{
dp[i][0] = a[i];
}
for(int j = 1; (1<<j)<=n ;j++)
{
for(int i = 1; i + (1<<j) - 1<=n ; i++)
{
dp[i][j] = min( dp[i][j - 1], dp[i + (1 << (j-1))][j - 1]);
}
}
}
int RMQ(int l,int r)
{
int k = 0 ;
while( 1<<(k+1) <=(r-l+1)) k++;
return min(dp[l][k],dp[r-(1<<k)+1][k]);
}
int lower_b(int l,int r,int ans)
{
int s = r+1;
while(l<=r)
{
int mid = (l+r)>>1;
if(RMQ(l,mid)<=ans)
{
r = mid - 1;
s = mid;
}
else
{
l = mid + 1;
}
}
return s;
}
int main()
{
int t;
while(scanf("%d",&t)!=EOF)
{
while(t--)
{
mes(dp);
mes(a);
scanf("%d",&n);
for(int i = 1 ; i <= n ; i++)
{
scanf("%d",&a[i]);
}
init();
int m,ans;
scanf("%d",&m);
while(m--)
{
int L,R;
scanf("%d%d",&L,&R);
ans = a[L];
L++;
while(L<=R&&ans)
{
L = lower_b(L,R,ans);
if(L<=R)
{
ans%=a[L];
L++;
}
}
printf("%d\n",ans);
}
}
}
}