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

37 篇文章 0 订阅
29 篇文章 0 订阅

题目描述
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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值