CodeForces 475D CGCDSSQ RMQ

通过这道题目还是学到了不少东西的,当时刚拿到这个题目的时候时间已经不多了,因为前面有个C坑到了,看了个大概,然后就往线段树和树状数组方面去想了,对于gcd的区间求一个前缀,再搞一个后缀 瞎弄弄,后来发现错了,题目求的是区间个数。。。又浪费了一段时间,然后回头再看看,大致就想到了暴力枚举,n是10^5,大不了离线先暴力的高出答案,想到一般发现  若假定一个询问输入的数 为  X,那么另一个 能够 y 通过gcd(x,y)得到的另一个数的 答案就是它自身的答案数再加上当前x的答案数,这样就有递推了,于是赶紧写了一下,结果T了!,没有做出来,补题也拖了很久。。。后来发现
自己的错误之处,其实对于G(l,r),G(l,r+1)后者肯定比前者更小,这句话在一个博客中也看到了,自己当时 顺序没写好。。。后来看到一个博客推荐的另一个 博客,发现了一个很好的解决办法

http://hplonline20100103.blog.163.com/blog/static/1361364342010040044244/

是以POJ3368为例子,然后看的半懂不懂的 ,磕磕碰碰的去把POJ3368给A了,又做了这道题目也过了,后来看CF的官方,题解发现了另一种解法,

http://blog.csdn.net/zearot/article/details/40180791 这篇博客就是第二种解法

枚举的是区间,然后利用两个map  类似于滚动数组一样进行传递再利用,保存在另一个map里,这个方法最好理解也非常简洁,参照他的 敲了一发 ,顺便纪念一下!

map<int ,ll> res;

map<int ,int >now,nex;

map<int ,int > ::iterator it;

int n;

int aa[100000 + 55];

int q;

void init() {
	memset(aa,0,sizeof(aa));
}

bool input() {
	while(cin>>n) {
		for(int i=0;i<n;i++)scanf("%d",&aa[i]);
		return false;
	}
	return true;
}

int Gcd(int a,int b) {
	return b == 0?a:Gcd(b,a%b);
}

void cal() {
	for(int i=0;i<n;i++) {
		nex.clear();
		for(it=now.begin();it!=now.end();it++)
			nex[Gcd(it->first,aa[i])] += it->second;
		nex[aa[i]]++;
		swap(nex,now);
		for(it = now.begin();it != now.end();it++)
			res[it->first] += it->second;
	}
	int q;
	cin>>q;
	while(q--) {
		int x;
		scanf("%d",&x);
		printf("%I64d\n",res[x]);
	}
}

void output() {

}

int main() {
	while(true) {
		init();
		if(input())return 0;
		cal();
		output();
	}
	return 0;
}
时间: 2024-08-25 07:10:08

CodeForces 475D CGCDSSQ RMQ的相关文章

Codeforces 475D CGCDSSQ(分治)

题意:给你一个序列a[i],对于每个询问xi,求出有多少个(l,r)对使得gcd(al,al+1...ar)=xi. 表面上是询问,其实只要处理出每个可能的gcd有多少个就好了,当左端点固定的时候,随着右端点的移动,gcd必然是单调非增的,而且个数不会超过log(a[i])个,所以总的不同的个数的上界是nlog(ai),所以求出所有是可行的. 一个分治的做法是这样的,对于一个区间[l,r],分治成[l,mid],[mid+1,r]求解,然后就是合并,合并的时候首先求以[l,mid]右端点为结束点

Codeforces 475D CGCDSSQ 求序列中连续数字的GCD=K的对数

题目链接:点击打开链接 #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <iostream> #include <cmath> using namespace std; typedef long long ll; template <class T> inline bool rd(T &ret)

CodeForces 52C Circular RMQ(区间循环线段树,区间更新,区间求和)

转载请注明出处:http://blog.csdn.net/u012860063 题目链接:http://codeforces.com/problemset/problem/52/C You are given circular array a0,?a1,?...,?an?-?1. There are two types of operations with it: inc(lf,?rg,?v) - this operation increases each element on the segm

Codeforces 803G Periodic RMQ Problem ST表+动态开节点线段树

思路: (我也不知道这是不是正解) ST表预处理出来原数列的两点之间的min 再搞一个动态开节点线段树 节点记录ans 和标记 lazy=-1 当前节点的ans可用  lazy=0 没被覆盖过 else 区间覆盖 push_up的时候要注意好多细节,, 数组尽量往大开 //By SiriusRen #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const in

CodeForces 279C Ladder (RMQ + dp)

题意:给定一个序列,每次一个询问,问某个区间是不是先增再降的. 析:首先先取处理以 i 个数向左能延伸到哪个数,向右能到哪个数,然后每次用RQM来查找最大值,分别向两边延伸,是否是覆盖区间. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include <string> #include <cstdlib> #include <c

CodeForces 52C Circular RMQ

线段树区间更新维护最小值...记得下放标记... 如果线段树上的一个完整区间被修改,那么最小值和最大值增加相应的值后不变, 会改变是因为一部分改变而另外一部分没有改变所以维护一下就好. 询问的时候也要记得下放标记... 数据结构快忘了,贴个板. #include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 2e5+1; struct Seg { ll lazy; ll Min; }tr[m

codeforces 475D

题意:给定n(n<=100000)个1e9以内的数的数组a,然后最多有3*1e5的询问,对于每个询问,给定一个x,问有多少个(l<=r&&gcd(a[l],a[l+1]...a[r]) == x) 思路:昨天的比赛题..可惜我被c题wa到放弃了这场比赛..也就没看了..不妨设G(l,r) = gcd(a[l], a[l+1]...a[r]); 其实题目最关键的的性质是对于G(l,r),G(l,r+1)后者肯定比前者更小.. 所以就可以暴力了..从后往前扫描i,处理(i, n)这

(WAWAWAWAWAWAW) G. Periodic RMQ Problem

没有联通门 : Codeforces G. Periodic RMQ Problem /* Codeforces G. Periodic RMQ Problem MMP 什么动态开点线段树啊 ... YY了个非常可行的做法 码完后交一下发现RE了几个点.. 就思考哪里有问题 突然之间, 老泪纵横.. MMP 我写了这是个什么玩意啊 仔细想想我TM不就是写了个全空间的主席树吗....脑子有病啊.. 静言思之, 躬自悼矣..反是不思,亦已焉哉 不写啦! */ #include <cmath> #i

codeforces 487B B. Strip(rmq+线段树+二分)

题目链接: codeforces 487B 题目大意: 给出一个序列,要把序列划分成段,每一段最少有L个元素,段中的最大元素和最小元素之差不大于s,问划分的段的最少的数量是多少. 题目分析: 首先用rmq维护区间最大值和区间最小值. 然后按顺序扫描数组,线段树维护的数组,每个记录当前点作为最后一个点的前i个点划分的最小的段数,那么每次更新就是二分找到可以转移到我的最远距离,然后再选取与我距离大于l的那部分,取最小值即可. 最终结果就是线段树维护的数组的最后一个位置的元素的值. AC代码: #in