HDU 5726 GCD(Sparse-Table+二分)
2017-02-21 16:36
357 查看
原题链接
Problem Description
Give you a sequence of N(N≤100,000) integers : a1,…,an(0< ai≤1000,000,000). There are Q(Q≤100,000) queries. For each query l,r you have to calculate gcd(al,,al+1,…,ar) and count the number of pairs(l′,r′)(1≤l< r≤N)such that gcd(al′,al′+1,…,ar′) equal gcd(al,al+1,…,ar).Input
The first line of input contains a number T, which stands for the number of test cases you need to solve.The first line of each case contains a number N, denoting the number of integers.
The second line contains N integers, a1,…,an(0< ai≤1000,000,000).
The third line contains a number Q, denoting the number of queries.
For the next Q lines, i-th line contains two number , stand for the li,ri, stand for the i-th queries.
Output
For each case, you need to output “Case #:t” at the beginning.(with quotes, t means the number of the test case, begin from 1).For each query, you need to output the two numbers in a line. The first number stands for gcd(al,al+1,…,ar) and the second number stands for the number of pairs(l′,r′) such that gcd(al′,al′+1,…,ar′) equal gcd(al,al+1,…,ar).
Sample Input
15
1 2 4 6 7
4
1 5
2 4
3 4
4 4
Sample Output
Case #1:1 8
2 4
2 4
6 1
题目大意
给出一个数组a,每次询问(l,r),问gcd(al,al+1,···ar)的值,以及在所有可能的l,r值中这个值的数目。解题思路
参考之前求解RMQ问题的思路,dp[i][j]表示从ai开始,长度为2j的序列的gcd,这样就有递推方程dp[i][j]=gcd(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
这样就可以O(nlogn)预处理,O(1)查询,接下来的问题就是如何统计出各个gcd值的数目。
首先可以枚举数列的起点,因为起点确定后,gcd的值是单调不升的,这样就可以通过二分查找查询出每个gcd有多少个值,通过map < int, long long>维护结果。
AC代码
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #include<cmath> #include<vector> #include<string> #include<queue> #include<list> #include<stack> #include<set> #include<map> #define ll long long #define ull unsigned long long #define rep(i,a,b) for (int i=(a),_ed=(b);i<_ed;i++) #define fil(a,b) memset((a),(b),sizeof(a)) #define cl(a) fil(a,0) #define pb push_back #define mp make_pair #define PI 3.1415927 #define inf 0x3f3f3f3f #define fi first #define se second #define VII vector<int,int> using namespace std; int dp[100005][20]; int a[100005]; int gcd(int a,int b) { if(!b) return a; return gcd(b,a%b); } int q(int l,int r) { int k=0; while((1<<(k+1))<=r-l+1) k++; int ans1=dp[l][k]; int ans2=dp[r-(1<<k)+1][k]; return gcd(ans1,ans2); } int main(void) { int t,n,m; cin>>t; for(int z=1;z<=t;++z) { map<int,ll> sum; printf("Case #%d:\n",z); scanf("%d",&n); for(int i=1;i<=n;++i) { scanf("%d",&a[i]); dp[i][0]=a[i]; } for(int j=1;j<=17;++j) { for(int i=1;i+(1<<j)-1<=n;++i) { dp[i][j]=gcd(dp[i][j-1],dp[i+(1<<(j-1))][j-1]); } } int ed=n+1; for(int u=1;u<=n;++u) { int i=u; while(i<=n) { ed=n+1; int st=i; while(ed>st) { int mid=(st+ed)>>1; if(q(u,i)==q(u,mid)) { st=mid+1; } else { ed=mid; } } sum[q(u,i)]+=(st-i); i=st; } } int l,r; scanf("%d",&m); for(int i=1;i<=m;++i) { scanf("%d%d",&l,&r); int res=q(l,r); printf("%d %I64d\n",res,sum[res]); } } return 0; }
相关文章推荐
- HDU 5726 GCD (RMQ + 二分)
- hdu 5726 GCD (二分+ST表)★
- HDU 5726 GCD(RMQ+二分)
- HDU 5726 GCD (RMQ + 二分)
- HDU 5726 GCD (rmq+二分 or 线段树 维护区间gcd)
- HDU 5726 GCD [RMQ+二分]
- HDU 5726 GCD(RMQ+二分)(线段树也可)
- HDU 5726-D-GCD- RMQ+二分
- Hdu 5726 GCD【思维+二分+区间Gcd】好题!
- HDU 5726 GCD(rmq+二分)
- HDU 5726 GCD(RMQ+二分)
- HDU 5726 GCD(ST+二分)
- HDU 5726 GCD(RMQ 查询 + 二分)
- hdu 5726 GCD RMQ+二分枚举
- HDU 5726 GCD(RMQ+二分,详解,ST算法)
- hdu 5726 区间gcd RMQ+二分 || 暴力枚举
- GCD HDU - 5726 (ST算法+二分)
- Hdu-5726 GCD (二分 + RMQ)
- HDU 5726 GCD (DP+二分)
- [HDU 5726] GCD (倍增法+二分)