zoukankan      html  css  js  c++  java
  • 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(N≤100,000)$ integers : $a_1,cdots,a_n(0<a_i≤1000,000,000)$. There are $Q(Q≤100,000)$ queries. For each query $l,r$ you have to calculate $ ext{gcd}(a_l,,a_{l+1},cdots,a_r)$ and count the number of pairs$(l′,r′)(1≤l<r≤N)$such that $ ext{gcd}(a_{l′},a_{l′+1},cdots,a_{r′})$ equal $ ext{gcd}(a_l,a_{l+1},...,a_{r})$.
     

    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, $a_1,cdots,a_n(0<a_i≤1000,000,000)$.

    The third line contains a number $Q$, denoting the number of queries.

    For the next $Q$ lines, $i ext{-th}$ line contains two number , stand for the $l_i,r_i$, stand for the $i ext{-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 $ ext{gcd}(a_l,a_{l+1}, cdots,a_r)$ and the second number stands for the number of pairs$(l′,r′)$ such that $ ext{gcd}(a_{l′},a_{l′+1},cdots,a_{r′})$ equal $ ext{gcd}(a_l,a_{l+1},cdots,a_r)$.
     

    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

     

    Author
    HIT
     

    Source
    2016 Multi-University Training Contest 1
     


    题意:

    支持查询: (1) 区间gcd, (2) gcd值等于k的区间数

    Solution:

    区间gcd的查询线段树即可解决, 另外还能支持单点修改. 但这题要求支持查询gcd值等于k的区间个数, 线段树就有点乏力了, 因为这个信息大概不太好通过合并区间信息来得到. 我们来考虑区间gcd的性质:

    令$gcd_r(l)quad (1le l le r) $表示, $l$到$r$的$gcd$. 不难看出:

    • $gcd_r(l)$随着$l$的增大是单调不减的
    • $gcd_r(l)$最多取$log{a_r}$个值, 因为在区间左端点从$r$移动到$l$的过程中gcd每缩小到一个新值都是因为除以了上个gcd的某个因子, 因而至少缩小为上个gcd的$frac{1}{2}$,  从而不同的区间$gcd$值最多有$log{a_r}$个

    因此, 我们可以对每个右端点$r$,  维护函数$gcd_r(l)$. 实现方法是:

    vector<pair<int,int>> f 存某个函数$gcd_r(l)$的每一段 (最多有$log{a_r}$段), f[i].first表示第$i$段的左端点, f[i].second表示第$i$段的函数值.

    在维护这$n$个函数的过程中, 用map记录每个$gcd$出现的次数 (不同$gcd$值最多有$O(nlog{N})$个, 实际上远达不到这个值.

    接下来我们考虑如何利用上面维护好的函数查询某个区间$[l,r]$的$gcd$.

    我们可以在函数$g_r(l)$中二分查询小于等于的$l$的first的最大值对应的second的值, 这便是答案.

    言不尽意, 详见代码.

    Implementation:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 const int N(1e5+5);
     5 typedef pair<int,int> P;
     6 
     7 vector<P> f[N];
     8 unordered_map<int,long long> cnt;
     9 int T, n, q, cs;
    10 
    11 int main(){
    12     for(cin>>T; T--; ){
    13         cin>>n;
    14         for(int i=1, gcd, pos; i<=n; i++){
    15             scanf("%d", &gcd), pos=i, f[i].clear();
    16             for(auto x:f[i-1]){
    17                 if(__gcd(gcd, x.second)!=gcd) f[i].push_back({pos, gcd});
    18                 gcd=__gcd(gcd, x.second), pos=x.first;        
    19             }
    20             f[i].push_back({pos, gcd});
    21         }
    22         cnt.clear();
    23         for(int i=1; i<=n; i++){
    24             int pos=i+1;
    25             for(auto x:f[i])
    26                 cnt[x.second]+=pos-x.first, pos=x.first;
    27         }
    28         cin>>q;
    29         printf("Case #%d:
    ", ++cs);
    30         for(int l, r; q--; ){
    31             scanf("%d%d", &l, &r);
    32             int gcd=lower_bound(f[r].begin(), f[r].end(), P(l, INT_MAX), greater<P>())->second;
    33             printf("%d %lld
    ", gcd, cnt[gcd]);
    34         }
    35     }
    36 }
     
     
  • 相关阅读:
    如何删除一个CSDN上自己上传的资源
    ubuntu 安装 boost
    C#-提取网页中的超链接
    数组地址详解
    约瑟夫环-源码
    树的基础概念(二)
    二叉树的主要操作
    二叉树的简介及链式结构实现
    树的基础概念
    栈实现数的进制转换
  • 原文地址:https://www.cnblogs.com/Patt/p/5742814.html
Copyright © 2011-2022 走看看