HDU 5381 The sum of gcd

The sum of gcd


Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)


Problem Description
You have an array  A,the length of  A is  n
Let  f(l,r)=ri=lrj=igcd(ai,ai+1....aj)
 

Input
There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case:
First line has one integers  n
Second line has  n integers  Ai
Third line has one integers  Q,the number of questions
Next there are Q lines,each line has two integers  l, r
1T3
1n,Q104
1ai109
1l<rn
 

Output
For each question,you need to print  f(l,r)
 

Sample Input
 
   
2 5 1 2 3 4 5 3 1 3 2 3 1 4 4 4 2 6 9 3 1 3 2 4 2 3
 

Sample Output
 
   
9 6 16 18 23 10

上一篇是用gcd性质处理出每个端点的gcd变化位置,这一篇是用了RMQ加二分预处理出所有的gcd变化位置,然后再用莫队算法求解。
类似的RMQ二分预处理还有 HDU 5726这一题。
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define maxn 50500
using namespace std;
typedef long long ll;
const int N = 10000 + 5;
int n, m;
int block;
int a[N];
ll ans[N];
int ggcd[23][maxn*2];
struct Node
{
        int L, R;
        int id;
        bool operator<(const Node&rhs)const
        {
                if (L / block == rhs.L / block)
                {
                        return R < rhs.R;
                }
                return L / block < rhs.L / block;
        }
} q[N];
int gcd(int a, int b)
{
        return (b == 0) ? a : gcd(b, a % b);
}
void ST(int num)
{
        for (int i = 1; i <= num; i++)
        {
                ggcd[0][i] = a[i];
        }
        for (int i = 1; i <= log2(num); i++)
                for (int j = 1; j <= num; j++)
                        if (j + (1 << i) - 1 <= num)
                        {
                                int a = ggcd[i - 1][j], b = ggcd[i - 1][j + (1 << i >> 1)];
                                ggcd[i][j]=gcd(a,b);

                        }
}
int RMQ(int x, int y)
{
        int k = (int) log2(y - x + 1.0);
        int a = ggcd[k][x], b = ggcd[k][y - (1 << k) + 1];
        return gcd(a,b);
}
struct He
{
        int idx;
        ll g;
};
vectorvl[N], vr[N];
void preDeal()
{
        ST(n);
        for(int i=1;i<=n;i++)
        {
                int g=ggcd[0][i],j=i;
                while(j<=n)
                {
                        int left = j,right=n,mid;
                        while(left <= right)
                        {
                                mid =(left + right)/2;
                                if(RMQ(i,mid)>=g)
                                {
                                        left =mid +1;
                                }
                                else
                                {
                                        right =mid -1;
                                }
                        }
                        mid = (left+right)/2;
                        vr[i].push_back(He{mid,g});
                        j=mid+1;
                        g=RMQ(i,j);
                }
        }
        for(int i=n;i>=1;i--)
        {
                int g=ggcd[0][i],j=i;
                while(j>=1)
                {
                        int left = 1,right=j,mid;
                        while(left <= right)
                        {
                                mid =(left + right)/2;
                                if(RMQ(mid,i)= L) //如果当前区间的左端点>=L,则当前区间为[it.idx,tr]
                        {
                                //这里其实用到了GCD值的传递性:
                                //如果L q[i].R) //向左移动右端点
                {
                        res -= calc(0, L, R);
                        R--;
                }
                while (L > q[i].L)
                {
                        L--;
                        res += calc(1, L, R);
                }
                while (L < q[i].L)
                {
                        res -= calc(1, L, R);
                        L++;
                }
                ans[q[i].id] = res; //转移完毕。注意,res,L,R都不要清零
        }
        for (int i = 0; i < m; i++)
        {
                printf("%I64d\n", ans[i]);
        }
}
int main()
{
        int T;
        scanf("%d", &T);
        while (T--)
        {
                scanf("%d", &n);
                for (int i = 1; i <= n; i++)
                {
                        scanf("%d", &a[i]);
                }
                scanf("%d", &m);
                for (int i = 0; i < m; i++)
                {
                        scanf("%d%d", &q[i].L, &q[i].R);
                        q[i].id = i;
                }
                solve();
        }
        return 0;
}

你可能感兴趣的:(莫队算法,RMQ,二分三分)