HDU_5729_rmq+二分
http://acm.hdu.edu.cn/showproblem.php?pid=5726
rmq修改成gcd的,关键是找个数,用二分来找,刚开始理解了好久,因为每个区间内gcd是递减的,所以可以优化暴力枚举。
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<map> using namespace std; int a[100005],n,dp[100005][20]; map<int,long long> mp; int gcd(int a,int b) { return b?gcd(b,a%b):a; } void rmq_init(int len) { for(int i = 1;i <= len;i++) { dp[i][0] = a[i]; } for(int j = 1;(1<<j) <= len;j++) { for(int i = 1;i+(1<<j)-1 <= len;i++) { dp[i][j] = gcd(dp[i][j-1],dp[i+(1<<(j-1))][j-1]); } } } int rmq_query(int l,int r) { int k = (int)(log((double)(r-l+1))/log(2.0)); return gcd(dp[l][k],dp[r-(1<<k)+1][k]); } int main() { int T; scanf("%d",&T); for(int z = 1;z <= T;z++) { mp.clear(); printf("Case #%d:\n",z); scanf("%d",&n); for(int i = 1;i <= n;i++) scanf("%d",&a[i]); rmq_init(n); for(int i = 1;i <= n;i++) { int l = i,r = i; while(r <= n) { int ll = r,rr = n; int v = rmq_query(l,r); while(ll <= rr) { int mid = (ll+rr)/2; if(rmq_query(l,mid) >= v) ll = mid+1; else rr = mid-1; } mp[v] += ll-r; r = ll; } } int t; scanf("%d",&t); while(t--) { int l,r; scanf("%d%d",&l,&r); int ans = rmq_query(l,r); printf("%d %lld\n",ans,mp[ans]); } } return 0; }