【HPU 1195 】Mod 【二分+打表】

来源:互联网 发布:手机制作纯音乐软件 编辑:程序博客网 时间:2024/06/16 01:06

题目描述
modmod是取余运算,在程序中用符号”%%”来表示。

如3%7=3,7%5=2,0%4=0。3%7=3,7%5=2,0%4=0。

Ocean用巧妙的方法得到了一个序列,该序列有NN个元素,我们用数组aa来记录(下标从00到N−1N−1)。

Ocean定义f[i]=(((i%a[0])%a[1])%…)%a[N−1]。f[i]=(((i%a[0])%a[1])%…)%a[N−1]。

现在Ocean会给出QQ次查询,每次给定一个区间[L,R],[L,R],他想快速知道∑Ri=Lf[i]∑i=LRf[i] (即f[L]+…+f[R]f[L]+…+f[R])的值。
输入
第一行输入一个整数TT,代表有TT组测试数据。
每组数据占多行,第一行输入一个整数NN,代表元素个数。
下面一行输入NN个整数aiai。
下面一行输入一个整数QQ,代表QQ次查询。
接下来QQ行,每行输入两个整数L,RL,R,代表查询的区间。

注:1<=T<=20,1<=N,Q<=1000,1<=ai<=100000,1<=L<=R<=100000。1<=T<=20,1<=N,Q<=1000,1<=ai<=100000,1<=L<=R<=100000。
输出
对每组测试数据,依次输出QQ行,每行输出对应的查询结果。
样例输入
2
5
5 4 3 2 1
4
1 100000
2 100000
3 100000
4 100000
5
5 5 5 5 5
4
1 100000
2 100000
3 100000
4 100000
样例输出
0
0
0
0
200000
199999
199997
199994
来源
CZY

觉得这题蛮有意思,就写写。 其实只要仔细想想就不是那么难,其实就是暴力,不过有的地方我们可以去进行一些优化,然后就可以过了。

代码
ac代码

#include<cstring>#include<cstdio> #include<cmath>#include<algorithm>using namespace std;typedef long long LL ;const int MAXN =  100000+10;const int MAXM = 1e5 ;const int mod  = 1e9+7 ;int arr[1000+10];int sum[MAXN];int main(){    int t;scanf("%d",&t);    while(t--){        int n;scanf("%d",&n);        int flag=0;int sz=1; // 这里我们可以去重,只有后面的数字比前面的小才起作用。这样做同时也将序列变成了单调的,才可以用二分        scanf("%d",&arr[0]); arr[0]=-arr[0];        for(int i=1;i<n;i++){            int a;scanf("%d",&a);            if(a==1) flag=1;            if(a<abs(arr[sz-1]))  arr[sz++]=-a;// 为什么这里 都要取一下负号呢。看下面二分的部分你就会明白了,我这里是为了二分方便        }       //      for(int i=0;i<sz;i++)  printf("%d ",arr[i]);//      printf("sz==%d\n",sz);        if(!flag){//只要数组中有 1,那么所有的f[i]都会是零。            sum[1]=1;            for(int i=2;i<=MAXN;i++){                int val=i;                 for(int j;;){//查找第一个可以对它取模有作用的位置                    j=lower_bound(arr,arr+sz,-val)-arr;                    if(j==sz||val==0) break;// 如果没有比它大的,即取模对其没有作用,或者已经取模为0了。这时候可以直接返回。                    val=val%(-arr[j]);                }                 sum[i]=sum[i-1]+val;            }        }        int q;int l,r;        scanf("%d",&q);        while(q--){            scanf("%d%d",&l,&r);            if(flag) puts("0");            else printf("%d\n",sum[r]-sum[l-1]);        }    }    return  0;}