hdu 5875 Function (st+二分)

来源:互联网 发布:ios小游戏源码 编辑:程序博客网 时间:2024/06/07 19:18

给你一个n,n个数

  m个询问,每次询问你 l,r,, a[l] % a[l+1] % a[l+2] %……a[r] 结果是多少

题解;

  每次有效的取模会使结果减半,因此只有log次有效取模,每次往右找一个不大于结果的最靠左的数,ST表+二分

一个数最多只能取 logn 次模
如果 x>y,那么 x mod y<=x/2

如果y <= x/2,那么 x mod y < y <= x/2

否则y > x/2,那么 x mod y = x-y < x /2

所以就很简单了= = 还有就是一些小操作要注意

#include <bits/stdc++.h>using namespace std;const int N = 1e5+100;int a[N];int mn[N][20];int n;void ST(){    for(int i=1;i<=n;i++)        mn[i][0]=a[i];    for(int j=1;(1<<j)<=n;j++)    {        for(int i=1;i+(1<<j)-1<=n;i++)        {            mn[i][j]=min(mn[i][j-1],mn[i+(1<<(j-1))][j-1]);        }    }}int rmq(int i,int j){    int k=0;    while(1<<(k+1)<=(j-i+1)) k++;    return min(mn[i][k],mn[j-(1<<k)+1][k]);}int bin(int l,int r,int res){        int s=r+1;        while(l<=r)        {            int md=(l+r)>>1;            if(rmq(l,md)<=res) r=md-1,s=md;            else l=md+1;        }        return s;}int main(){    int t;    while(scanf("%d",&t)!=EOF)    {        while(t--)        {        scanf("%d",&n);        for(int i=1;i<=n;i++)        {            scanf("%d",&a[i]);        }        ST();        int m;        scanf("%d",&m);        for(int i=1;i<=m;i++)        {            int f=0;            int ll,rr;            scanf("%d%d",&ll,&rr);            int res=a[ll];            int L=ll+1,R=rr;            while(L<=R&&res)             {                L=bin(L,R,res);                if(L<=R)                {                    res%=a[L],L++;                }            }            printf("%d\n",res );        }        }    }}
原创粉丝点击