分析:
给出一串数,然后进行区间查询,每次查询一个区间的gcd,并且要求同时输出和这个区间gcd值相等的其它区间的个数。题解:
1.RMQ快速区间查询:(此处查询的是GCD)
int dp[Maxn][21];//dp[i][j]表示从 number[i]开始,长度为2^j次的区间的最值
void init()
{
for (int i = 0; i < N; i++) //dp前的预处理,把数组读进去
dp[i][0] = numbers[i];
for (int j = 1; (1<<j) <= N; j++)//RMQ的初始化操作
{
for (int i = 0; i+(1<<j)-1 < N; i++)
{
dp[i][j] = __gcd (dp[i][j-1], dp[i+(1<<(j-1))][j-1]);
}
}
}
int query(int l, int r) // 查询区间最值
{
int k = 0;
while ((1<<(k+1)) <= r-l+1)
k++;
return __gcd (dp[l][k], dp[r-(1<<k)+1][k]);
}
2.二分处理相同GCD区间个数:
map <int, long long> gg; // first记录gcd值, second 记录相同gcd值下的区间个数
void solve ()
{
for (int i = 0; i < N; i++) //枚举左端点
{
int pos = N-1;
while (pos >= i) //二分选定右端点
{
int tmp = query(i, pos);
int l = i, r = pos;
while (r-l > 1)
{
int mid = (l+r)>>1;
if (query(i, mid) == tmp) r = mid;
else l = mid;
}
int cur;
if (query(i, l) == tmp)
cur = l;
else
cur = r;
gg[tmp] += (pos-cur+1); // 表示区间[i, pos] 与 区间[i, cur+1]的GCD值相等,且等于tmp,所以gcd值等于tmp的数量由pos-cur+1
pos = cur-1;
}
}
}
- 参考代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<map>
#include<algorithm>
#define Maxn 112345
using namespace std;
typedef long long LL;
LL numbers[Maxn];
int dp[Maxn][21]; //dp[i][j]表示从 number[i]开始,长度为2^j次的区间的最值
map <int, long long> gg; // first记录gcd值, second 记录相同gcd值下的区间个数
int N;
void init()
{
for (int i = 0; i < N; i++) //dp前的预处理,把数组读进去
dp[i][0] = numbers[i];
for (int j = 1; (1<<j) <= N; j++)//RMQ的初始化操作
{
for (int i = 0; i+(1<<j)-1 < N; i++)
{
dp[i][j] = __gcd (dp[i][j-1], dp[i+(1<<(j-1))][j-1]);
}
}
}
int query(int l, int r) // 查询区间最值
{
int k = 0;
while ((1<<(k+1)) <= r-l+1)
k++;
return __gcd (dp[l][k], dp[r-(1<<k)+1][k]);
}
void solve ()
{
for (int i = 0; i < N; i++) //枚举左端点
{
int pos = N-1;
while (pos >= i) //二分选定右端点
{
int tmp = query(i, pos);
int l = i, r = pos;
while (r-l > 1)
{
int mid = (l+r)>>1;
if (query(i, mid) == tmp) r = mid;
else l = mid;
}
int cur;
if (query(i, l) == tmp)
cur = l;
else
cur = r;
gg[tmp] += (pos-cur+1); // 表示区间[i, pos] 与 区间[i, cur+1]的GCD值相等,且等于tmp,所以gcd值等于tmp的数量由pos-cur+1
pos = cur-1;
}
}
}
int main()
{
int t;
cin >> t;
int tt = 1;
while(t--)
{
printf ("Case #%d:\n", tt++);
gg.clear ();
scanf("%d", &N);
for(int i=0;i<N;i++)
{
scanf("%lld", &numbers[i]);
}
init();
solve ();
int Q;
scanf("%d", &Q);
while (Q--)
{
int l , r;
scanf("%d%d", &l, &r);
int ans = query(l-1, r-1);
printf ("%d %lld\n", ans, gg[ans]);
}
}
return 0;
}