zoukankan      html  css  js  c++  java
  • HDU 4676 Sum Of Gcd 【莫队 + 欧拉】

    任意门:http://acm.hdu.edu.cn/showproblem.php?pid=4676

    Sum Of Gcd

    Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)
    Total Submission(s): 908    Accepted Submission(s): 438


    Problem Description
    Given you a sequence of number a1, a2, ..., an, which is a permutation of 1...n.
    You need to answer some queries, each with the following format:
    Give you two numbers L, R, you should calculate sum of gcd(a[i], a[j]) for every L <= i < j <= R.
     
    Input
    First line contains a number T(T <= 10),denote the number of test cases.
    Then follow T test cases.
    For each test cases,the first line contains a number n(1<=n<= 20000).
    The second line contains n number a1,a2,...,an.
    The third line contains a number Q(1<=Q<=20000) denoting the number of queries.
    Then Q lines follows,each lines contains two integer L,R(1<=L<=R<=n),denote a query.
     
    Output
    For each case, first you should print "Case #x:", where x indicates the case number between 1 and T.
    Then for each query print the answer in one line.
     
    Sample Input
    1
    5
    3 2 5 4 1
    3
    1 5
    2 4
    3 3
     
    Sample Output
    Case #1:
    11
    4
    0
     
    Source

    题意概括:

    给出 1~N 的一个排列,M次查询,每次查询 L ~ R 内 GCD( ai, aj )  [ L <= i < j <= R ] 的总和。

    解题思路:

    又是涉及 GCD 又是 涉及区间查询,头有点大。

    首先莫队处理区间查询,其次欧拉函数解决GCD问题。

    根据:

     

    那么用 gcd( ai, aj) 代替上式的 n,我们可以得到:

    问题就转换成了求 d 的欧拉函数,其实 d 是有很多重复的,那么我们只要统计出当前查询区间【L,R】内 d 出现的次数然后乘上其欧拉函数值,所求的的答案就是区间GCD的总和。

    欧拉函数值和对原序列的每一项的因数分解预处理时搞定。

    AC code:

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <algorithm>
     4 #include <cstring>
     5 #include <vector>
     6 #include <cmath>
     7 #define INF 0x3f3f3f3f
     8 #define LL long long
     9 using namespace std;
    10 
    11 const int MAXN = 2e4+20;
    12 int unit, a[MAXN], N, M, cnt[MAXN];
    13 LL ans[MAXN], phi[MAXN];
    14 vector<int>factor[MAXN];
    15 
    16 struct Query
    17 {
    18     int l, r, idx;
    19     friend bool operator < (const Query & a, const Query & b){
    20         int x1 = a.l/unit, x2 = b.l/unit;
    21         if(x1 != x2) return x1 < x2;
    22         return a.r < b.r;
    23     }
    24 }Q[MAXN];
    25 
    26 void init()
    27 {
    28     for(int i = 1; i < MAXN; i++){      //分解因子
    29         for(int j = i; j < MAXN; j+=i)
    30             factor[j].push_back(i);
    31     }
    32 
    33     phi[1] = 1;                         //欧拉函数
    34     for(int i = 2; i < MAXN; i++){
    35         phi[i] = i;
    36     }
    37     for(int i = 2; i < MAXN; i++){
    38         if(phi[i] == i){
    39             for(int j = i; j < MAXN; j+=i)
    40                 phi[j] = phi[j]/i*(i-1);
    41         }
    42         //puts("zjy");
    43     }
    44 }
    45 
    46 LL add(int x)
    47 {
    48     LL res = 0;
    49     for(auto d : factor[x]) res+=cnt[d]*phi[d];
    50     for(auto d : factor[x]) cnt[d]++;
    51     return res;
    52 }
    53 
    54 LL del(int x)
    55 {
    56     LL res = 0;
    57     for(auto d : factor[x]) cnt[d]--;
    58     for(auto d : factor[x]) res+=cnt[d]*phi[d];
    59     return -res;
    60 }
    61 
    62 
    63 void solve()
    64 {
    65     memset(cnt, 0, sizeof(cnt));
    66     int L = 1, R = 0;
    67     LL cur = 0;
    68     for(int i = 1; i <= M; i++){
    69         while( L < Q[i].l) cur += del(a[L++]);
    70         while( L > Q[i].l) cur += add(a[--L]);
    71         while( R < Q[i].r) cur += add(a[++R]);
    72         while( R > Q[i].r) cur += del(a[R--]);
    73         ans[Q[i].idx] = cur;
    74         //puts("zjy");
    75     }
    76 }
    77 
    78 int main()
    79 {
    80     int T_Case, Cas = 0;
    81     init();
    82     //puts("zjy");
    83     scanf("%d", &T_Case);
    84     while(T_Case--){
    85         scanf("%d", &N);
    86         for(int i = 1; i <= N; i++) scanf("%d", &a[i]);
    87         scanf("%d", &M);
    88         for(int i = 1; i <= M; i++){
    89             scanf("%d %d", &Q[i].l, &Q[i].r);
    90             Q[i].idx = i;
    91         }
    92         unit = sqrt(N);
    93         sort(Q+1, Q+1+M);
    94         solve();
    95         printf("Case #%d:
    ", ++Cas);
    96         for(int i = 1; i <= M; i++) printf("%lld
    ", ans[i]);
    97     }
    98     return 0;
    99 }
  • 相关阅读:
    正则表达式
    9.4、分布式进程
    Linux文件编辑工具——VIM
    14 Linux网络管理
    13.Linux系统服务
    12.Linux进程管理
    11.Linux磁盘管理——lvm,raid
    10.Linux磁盘管理
    09.Linux软件包管理——(YUM 、RPM)
    07.Linux 压缩打包
  • 原文地址:https://www.cnblogs.com/ymzjj/p/10390012.html
Copyright © 2011-2022 走看看