zoukankan      html  css  js  c++  java
  • hdu1695(莫比乌斯反演模板)

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1695

    题意: 对于 a, b, c, d, k . 有 x 属于 [a, b],  y 属于 [c, d], 求 gcd(x, y) = k 的 x, y 的对数 . 其中 a = b = 1 .

    注意: (x, y), (y, x) 算一种情况 .

    思路: 莫比乌斯反演

    可以参考一下: http://blog.csdn.net/lixuepeng_001/article/details/50577932

    公式: F(n) = sigma f(d) , 其中 (n | d) ==> f(n) = sigma u(d / n) * F(d) , 其中 (n | d) .

    其中 u 为莫比乌斯函数, 定义为:

      若 d = 1, 则 u(d) = 1;

      若 d = p1p2...pk, 则 u(d) = (-1)^k , 其中 pi 为互异质数;

      其他 u(d) = 0;

    对于 gcd(x, y) = k, 显然有 gcd(x / k, y / k) = 1 . 那么原题等价于求 gcd(x, y) = 1, 其中 x 属于 (1, b / k), y 属于 (1, d / k) .

    然后定义 f(n) 表示满足条件的 gcd(x,y) = n 的 (x, y) 对数,

    再定义 F(n) 表示满足 n | gcd(x,y) 的 (x, y) 对数, 即 gcd(x, y) % n = 0 的x, y对数 .

    那么我们要求的就是 f(1) .

    通过前面推理不难发现 F(x) = n / x * m / x, 其中 n = b / k, m = d / k;

    那么 f(1) = sigma u(d / 1) * F(d), 其中 1 | d 且 d <= min(n, m);

    即 f(1) = sigma u(d) * (n / d) * (m / d);

    关于去重: f'(1) = sigma u(d) * (n / d) * (n / d), 其中 n 为 m, n中的最小值, 则 sol = f(1) - f'(1) / 2;

    代码:

     1 #include <iostream>
     2 #include <stdio.h>
     3 #include <string.h>
     4 #define ll long long
     5 using namespace std;
     6 
     7 const int MAXN = 1e6 + 10;
     8 
     9 bool check[MAXN];
    10 int mu[MAXN], prime[MAXN];
    11 
    12 void Moblus(void){
    13     memset(check, false, sizeof(check));
    14     int tot = 0;
    15     mu[1] = 1;
    16     for(int i = 2; i < MAXN; i++){
    17         if(!check[i]){
    18             prime[tot++] = i;
    19             mu[i] = -1;
    20         }
    21         for(int j = 0; j < tot && i * prime[j] < MAXN; j++){
    22             check[i * prime[j]] = true;
    23             if(i % prime[j] == 0){
    24                 mu[i * prime[j]] = 0;
    25                 break;
    26             }else mu[i * prime[j]] = -mu[i];
    27         }
    28     }
    29 }
    30 
    31 int main(void){
    32     int t, a, b, c, d, k;
    33     Moblus();
    34     scanf("%d", &t);
    35     for(int i = 1; i <= t; i++){
    36         scanf("%d%d%d%d%d", &a, &b, &c, &d, &k);
    37         if(k == 0){
    38             printf("Case %d: 0
    ", i);
    39             continue;
    40         }
    41         if(b > d) swap(b, d);
    42         b /= k;
    43         d /= k;
    44         ll ans1 = 0, ans2 = 0;
    45         for(int j = 1; j <= b; j++){
    46             ans1 += (ll)mu[j] * (b / j) * (d / j);
    47         }
    48         for(int j = 1; j <= b; j++){
    49             ans2 += (ll)mu[j] * (b / j) * (b / j);
    50         }
    51         printf("Case %d: %lld
    ",i, ans1 - (ans2 >> 1));
    52     }
    53     return 0;
    54 }
    View Code

    因为对于某些连续的 i 会有 b / i, d / i 是相同的, 这种情况可以通过前缀和优化一下 .

    优化代码:

     1 #include <iostream>
     2 #include <stdio.h>
     3 #include <string.h>
     4 #define ll long long
     5 using namespace std;
     6 
     7 const int MAXN = 1e5 + 10;
     8 
     9 bool check[MAXN];
    10 int prime[MAXN], mu[MAXN], sum[MAXN];
    11 
    12 void Moblus(void){
    13     memset(check, false, sizeof(check));
    14     int tot = 0;
    15     mu[1] = 1;
    16     sum[1] = 1;
    17     for(int i = 2; i < MAXN; i++){
    18         if(!check[i]){
    19             prime[tot++] = i;
    20             mu[i] = -1;
    21         }
    22         for(int j = 0; j < tot && prime[j] * i < MAXN; j++){
    23             check[i * prime[j]] = true;
    24             if(i % prime[j] == 0){
    25                 mu[i * prime[j]] = 0;
    26                 break;
    27             }else mu[i * prime[j]] = -mu[i];
    28         }
    29         sum[i] = sum[i - 1] + mu[i];
    30     }
    31 }
    32 
    33 ll solve(int b, int d){
    34     ll ans = 0;
    35     for(int i = 1, la = 0; i <= b; i = la + 1){
    36         la = min(b / (b / i), d / (d / i));
    37         ans += (ll)(sum[la] - sum[i - 1]) * (b / i) * (d / i);
    38     }
    39     return ans;
    40 }
    41 
    42 int main(void){
    43     Moblus();
    44     int t, a, b, c, d, k;
    45     scanf("%d", &t);
    46     for(int i = 1; i <= t; i++){
    47         scanf("%d%d%d%d%d", &a, &b, &c, &d, &k);
    48         if(k == 0){
    49             printf("Case %d: 0
    ", i);
    50             continue;
    51         }
    52         b /= k;
    53         d /= k;
    54         if(b > d) swap(b, d);
    55         ll ans1 = solve(b, d);
    56         ll ans2 = solve(b, b);
    57          printf("Case %d: %lld
    ", i, ans1 - (ans2 >> 1));
    58     }
    59     return 0;
    60 }
    View Code

    就本题而言时间从 31ms 优化到了 15 ms .

  • 相关阅读:
    BEM(Block–Element-Modifier)
    http://element.eleme.io/#/zh-CN/component/quickstart
    Commit message 的写法规范。本文介绍Angular 规范(
    好的commit应该长啥样 https://github.com/torvalds/linux/pull/17#issuecomment-5654674
    代码管理
    if you have content fetched asynchronously on pages where SEO is important, SSR might be necessary
    Martin Fowler’s Active Record design pattern.
    The Zen of Python
    Introspection in Python How to spy on your Python objects Guide to Python introspection
    Object-Oriented Metrics: LCOM 内聚性的度量
  • 原文地址:https://www.cnblogs.com/geloutingyu/p/7247863.html
Copyright © 2011-2022 走看看