题解:
1.线段树用来区间查询,至于数量统计可以之前暴力打个表,丢在map里查询即可
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#include <string>
#include <map>
#include <math.h>
#include <queue>
#include <climits>
#include <stack>
using namespace std;
int g[100005<<2], cnt;
int cas = 0;
int ss[100005];
int gcd(int a, int b)
{
if(b == 0) return a;
else return gcd(b, a%b);
}
void build(int x, int l, int r)
{
if(l == r){
scanf("%d", &g[x]);
ss[l] = g[x];
}
else{
int mid = (l + r) / 2;
build(x<<1, l, mid);
build(x<<1|1, mid + 1, r);
g[x] = gcd(g[x<<1], g[x<<1|1]);
}
}
int get(int x, int l, int r, int ll, int rr)
{
if(ll <= l && rr >= r)
return g[x];
int mid = (l + r) / 2;
int ans = 0;
if(ll <= mid)
ans = gcd(ans, get(x<<1, l, mid, ll, rr));
if(rr > mid)
ans = gcd(ans, get(x<<1|1, mid + 1, r, ll, rr));
return ans;
}
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
int n;
cnt = 1;
scanf("%d", &n);
build(1, 1, n);
map<int, long long> m1, m2, answer;
m1[ss[1]]++;
answer[ss[1]]++;
for(int i = 2; i <= n; i++)
{
int now = ss[i];
m2[now]++;
answer[now]++;
for(auto it = m1.begin(); it != m1.end(); it++)
{
int next = gcd(now, it->first);
answer[next] += it->second;
m2[next] += it->second;
}
m1.clear();
m1 = m2;
m2.clear();
}
int q;
printf("Case #%d:\n", ++cas);
scanf("%d", &q);
while (q--) {
int a, b;
scanf("%d%d", &a, &b);
int ans = get(1, 1, n, a, b);
printf("%d %lld\n", ans, answer[ans]);
}
}
return 0;
}
2.RMQ + 二分,预处理出结果,查询只要O(1)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#include <string>
#include <map>
#include <math.h>
#include <queue>
#include <climits>
#include <stack>
using namespace std;
const int maxn = 1e5 + 5;
int a[maxn];
int dp[maxn][19];
int n;
int gcd(int a, int b)
{
if(b == 0) return a;
else return gcd(b, a%b);
}
void init()
{
for(int i = 1; i <= n; i++)
dp[i][0] = a[i];
for(int j = 1; j <= 18; 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 rmq(int a, int b)
{
int k = 0;
while(a + (1<<k) <= b + 1) k++;
k--;
return gcd(dp[a][k], dp[b - (1<<k) + 1][k]);
}
int fun(int start, int l, int r, int g)
{
int pos = r + 1;
while(l < r)
{
int mid = (l + r) / 2;
if(rmq(start, mid) < g){
r = mid;
pos = r;
}
else{
l = mid + 1;
pos = l;
}
}
return pos;
}
int main()
{
int t, cas = 1;
scanf("%d", &t);
while(t--)
{
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%d", &a[i]);
init();
map<int, long long> m;
for(int i = 1; i <= n; i++)
for(int k = i; k <= n;)
{
int pos = fun(i, k, n, rmq(i, k));
m[rmq(i, k)] += pos - k;
k = pos;
}
printf("Case #%d:\n", cas++);
int q;
scanf("%d", &q);
while(q--)
{
int a, b;
scanf("%d%d", &a, &b);
int ans = rmq(a, b);
printf("%d %lld\n", ans, m[ans]);
}
m.clear();
}
return 0;
}