题目:http://acm.hdu.edu.cn/showproblem.php?pid=5875
题意:给定一个数组,并给出[l,r],要求求出A(l)%A(l+1)%......%A(r)的值,当l==r时 直接等于A(l)
题解:这道题的意思就是每次找到区间内最靠近l的且比当前ans小的进行取模,每次都这么取,知道到r,可以利用rmq算法先用o(nlogn)进行预处理,然后查找时的复杂度就只有o(1),每次快速查找最靠近的最小值
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
int dp[100050][25];
void rmq(int num)//o(nlogA)
{
for(int j=1;(1<<j)<=num;j++)
{
for(int i=1;i<=num;i++)
{
if(i+(1<<j)-1<=num)
{
dp[i][j]=min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
}
}
}
}
int query(int l,int r)
{
if(l>r) return 1000000005;
int len=r-l+1;
int k=0;
while((1<<(k+1))<=len) k++;
return min(dp[l][k],dp[r-(1<<(k))+1][k]);
}
int main()
{
int t,m,q;
scanf("%d",&t);
while(t--)
{
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d",&dp[i][0]);
}
rmq(m) ;
scanf("%d",&q);
for(int i=1;i<=q;i++)
{
int l,r;
scanf("%d %d",&l,&r);
int ans=dp[l][0];
bool flag=0;
if(l==r) {printf("%d\n",ans);continue;};
l++;
while(l<=r)
{
int left=l,right=r;
while(left<right)
{
int mid=(left+right)/2;
if(query(left,mid)<=ans) right=mid;
else if(query(mid+1,right)<=ans) left=mid+1;
else {flag=1;break;}
}
if(flag) break;
l=left;
ans%=dp[l][0];
l++;//必须加1,不然可以取自己
}
printf("%d\n",ans);
}
}
return 0;
}
附录:
rmq-st算法:http://blog.csdn.net/niushuai666/article/details/6624672/
http://blog.csdn.net/liang5630/article/details/7917702