HPU 1195: Mod [STL、二分、单调队列、DFS]

Mod

时间限制: 4000 ms  |  内存限制: 65535 KB
难度: 2
描述
mod是取余运算,在程序中用符号"%"来表示。

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

Ocean用巧妙的方法 得到了一个序列,该序列有 N N 个元素,我们用数组 a a 来记录(下标从 0 0 到 N1

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
来源
第七届河南理工大学程序设计大赛


AC代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
 
using namespace std;

typedef long long LL;
const int MAXN=1e5+1;

bool vis[MAXN+11]; 
int a[1011],ans[MAXN+11];
queue<int> Q;

int B_S(int n,int cnt) {//很快的 就差这一个数量级 
	int L=0,R=cnt;
	while(L<R) {
		int mid=L+R>>1;
		if(a[mid]<=n) {
			R=mid-1;
		}
		else L=mid+1;
	}
	return L;
}
int main() {
	int T; scanf("%d",&T);
	while(T-- ) {
		int N; scanf("%d",&N);
		int cnt=0;
		for(int i=0;i<N;++i) {
			int tem; scanf("%d",&tem);
			if(i==0||tem<a[cnt-1]) a[cnt++]=tem;
		} 
		memset(vis,false,sizeof(vis));
		int i=0;
	    for(i=1;i<a[cnt-1];++i) {
	    	ans[i]=i; vis[i]=true;
		}
		for( ;i<MAXN;++i) {
		    int tem=i;
		    for(int j=B_S(tem,cnt);j<cnt;++j) {
		    	if(vis[tem]) break;
		        Q.push(tem);
		        tem%=a[j];	
			}
			while(!Q.empty() ) {
				int F=Q.front(); Q.pop();
				if(!vis[F]) {
					vis[F]=true;
					ans[F]=ans[tem];
				}
				else break;
			}
			while(!Q.empty()) Q.pop();
		}
		ans[0]=0;
		for(int i=1;i<MAXN;++i) ans[i]+=ans[i-1];
		int ask; scanf("%d",&ask);
		while(ask--) {
			int L, R; scanf("%d%d",&L,&R);
			printf("%d\n",ans[R]-ans[L-1]);
		}
	} 
	return 0;
} 




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值