HDU 5726 GCD

GCD


Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)



Problem Description
Give you a sequence of  N(N100,000)  integers :  a1,...,an(0<ai1000,000,000) . There are  Q(Q100,000)  queries. For each query  l,r  you have to calculate  gcd(al,,al+1,...,ar)  and count the number of pairs (l,r)(1l<rN) 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<ai1000,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
  
  
1 5 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

 直接RMQ预处理+二分查找T了。因为查询次数太多,其实gcd种类数目不多,所以可以先预处理开个map记录gcd为某个值的数目。
先for循环遍历区间起点,然后二分查找每次区间gcd变化时的终点,存到map中。
/*
RMQ-ST算法 + 二分预处理
查询次数太多,不能直接二分查询
因为GCD其实最多只有nlog2(n)种 所以可以先预处理在map中
*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <set>
#include <map>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <bitset>
#include <string>
#include <vector>
#include <iomanip>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <functional>
#define inf 0x7fffffff
#define maxn 100010
using namespace std;
int gcd[23][maxn*2];
int a[maxn];
long long ans;
int n, q;
void ST(int num)
{
        for (int i = 1; i <= num; i++)
        {
                gcd[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 = gcd[i - 1][j], b = gcd[i - 1][j + (1 << i >> 1)];
                                gcd[i][j]=__gcd(a,b);

                        }
}
int RMQ(int x, int y)
{
        int k = (int) log2(y - x + 1.0);
        int a = gcd[k][x], b = gcd[k][y - (1 << k) + 1];
        return __gcd(a,b);
}
int main()
{
        int T;
        scanf("%d", &T);
        for(int tt=1;tt<=T;tt++)
        {

                scanf("%d", &n);
                for (int i = 1; i <= n; i++)
                {
                        scanf("%d", &a[i]);
                }
                ST(n);
                scanf("%d",&q);
                printf("Case #%d:\n",tt);
                map<int,long long> mp;
                for(int i=1;i<=n;i++)
                {
                        int g=gcd[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;
                                mp[g]+=(mid-j+1);
                                j=mid+1;
                                g=RMQ(i,j);
                        }
                }
                while(q--)
                {
                        int a,b;
                        scanf("%d %d",&a,&b);
                        int ans=RMQ(a,b);
                        printf("%d %I64d\n",ans,mp[ans]);
                }
        }
        return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值