poj5875 Function(st + 二分)
题目描述
就是给你n个数,m次询问,每一次询问给你[l,r]每次询问求出a[l] % a[l+1] % a[l+2] %……a[r] 的结果是多少
题目解析
每次有效的取模会使结果减半,因此只有log次有效取模,每次往右找一个不大于结果的最靠左的数,ST表+二分
注意RMQ查询的时候少用 log函数
Code
#include<iostream> #include<algorithm> using namespace std; typedef long long ll; const int maxn=2e5+100; ll Min[maxn][33]; ll a[maxn]; int Log[maxn]; int n,m; void GetLog(){ Log[1]=0; for(int i=2;i<=n+1;i++){ Log[i]=Log[i/2]+1; } } void RMQ(){ for(int i=1;i<=n;i++){ Min[i][0]=a[i]; } for(int j=1;(1<<j)<=n;j++){ for(int i=1;i+(1<<(j-1))<=n;i++){ Min[i][j]=min(Min[i][j-1],Min[i+(1<<(j-1))][j-1]); } } } ll query_min(int l,int r){ int k=Log[r-l+1]; return min(Min[l][k],Min[r-(1<<k)+1][k]); } int lower(int x,int y,int ans){ int l=x,r=y,res=y+1; while(l<=r){ int mid=(l+r)/2; if(query_min(x,mid)<=ans){ res=mid; r=mid-1; } else{ l=mid+1; } } return res; } int main(){ int _; cin>>_; while(_--){ cin>>n; for(int i=1;i<=n;i++){ scanf("%lld",&a[i]); } GetLog(); RMQ(); scanf("%d",&m); int x,y,l,r; for(int i=1;i<=m;i++){ scanf("%d%d",&x,&y); ll ans=a[x]; l=x+1,r=y; while(l<=r&&ans){ l=lower(l,r,ans); if(l<=r){ ans%=a[l]; l++; } } printf("%lld\n",ans); } } }