1、题目信息
Mod
时间限制:
4000 ms | 内存限制:
65535 KB
难度:
2
- 描述
-
mod是取余运算,在程序中用符号"%"来表示。
如3 % 7 = 3,7 % 5 = 2,0 % 4 = 0。
Ocean用巧妙的方法得到了一个序列,该序列有 NN 个元素,我们用数组 aa 来记录(下标从 00 到 N−1
Ocean定义f[i] = (((i % a[0]) % a[1]) % ...) % a[N-1]。
现在Ocean会给出Q次查询,每次给定一个区间[L, R],他想快速知道f[L] + ... + f[R]的值。
- 输入
-
第一行输入一个整数T,代表有T组测试数据。
每组数据占多行,第一行输入一个整数N,代表元素个数。
下面一行输入N个整数ai。
下面一行输入一个整数Q,代表Q次查询。
接下来Q行,每行输入两个整数L, R,代表查询的区间。
注:1 <= T <= 20,1 <= N,Q <= 1000,1 <= ai <= 100000,1 <= L <= R <= 100000。 - 输出
- 对每组数据,依次输出Q行,每行输出对应的查询结果。
- 样例输入
-
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
2、思路
1)这个题目数据规模比较大,适合使用打表法(一次性将所有数据计算出来,存入数组中)
2)多次取余,如果后面的除数大于前面的,无效可以去除
3)使用二分查找(这里使用c++模板库的lower_bound()函数)
4)如果除数列表中有1,则所有结果都是0
3、代码
#include <stdio.h> #include <algorithm> #include <math.h> #define MaxSize_1 1010 #define MaxSize_2 100010 using namespace std; int a[MaxSize_2]={0};//存放打表数据 int b[MaxSize_1];//存放除数 int main(){ int t,m; scanf("%d",&t); while(t--){ int temp,flag=0,index=0;//temp用来暂时存放除数;flag标记除数序列是否有1;index作为除数序列的下标 scanf("%d",&m); scanf("%d",&b[0]);//首先存取除数中的第一个,方便判断后续除数的大小,进而选择是否保留 //这里除数序列取负,是为了使用lower_bound()函数时,不断找到小于被除数的除数 b[0]=-b[0]; for(int i=1;i<m;i++){ scanf("%d",&temp); if(temp==1) flag=1; else{ if(temp<abs(b[index])){ b[++index]=-temp; } } } if(!flag){//如果b数组中没有1,打标 for(int i=1;i<MaxSize_2;i++){ int k=i; for(int j;;){ //lower_bound()函数返回的是大于等于待查数的下标,否则返回数组的右边界(注意右边界是开区间) j=lower_bound(b,b+index+1,-k)-b; if(j==index+1) break; k=k%(-b[j]); } a[i]=a[i-1]+k; } } int q,l,r; scanf("%d",&q); while(q--){ scanf("%d%d",&l,&r); if(flag) printf("0\n"); else{ printf("%d\n",a[r]-a[l-1]); } } } return 0; }