題目: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