zoukankan      html  css  js  c++  java
  • YY的GCD 莫比乌斯反演

    ~~~题面~~~

    题解:

    $ans = sum_{x = 1}^{n}sum_{y = 1}^{m}sum_{i = 1}^{k}[gcd(x, y) == p_{i}]$其中k为质数个数
        $$ans = sum_{i = 1}^{k}sum_{x = 1}^{n}sum_{y = 1}^{m}[gcd(x, y) == p_{i}]$$
        设$f(d)$表示$x$从$1$到$n$,$y$从$1$到$m$,$gcd == d$的个数,$g(d)$表示相同条件下$d | gcd$(即$gcd$为$d$的倍数)的个数
        那么$$f(d) = sum_{x = 1}^{n}sum_{y = 1}^{m}[gcd(x, y) == d]$$,$$g(d) = lfloor{frac{n}{d}} floorlfloor{frac{m}{d}} floor$$
        因为$$g(x) = sum_{x|d}^{min(n, m)}f(d)$$
        所以反演一下。
        $$f(x) = sum_{x | d}^{min(n, m)}mu(frac{d}{x})g(d)$$
        那么$ans = sum_{i = 1}^{k}f(p_{i})$
        $$= sum_{i = 1}^{k}sum_{x | d}^{min(n, m)}mu(frac{d}{x})g(d)$$
        改成直接枚举系数
        $$= sum_{i = 1}^{k}sum_{d = 1}^{lfloor{frac{min(n, m)}{p_{i}}} floor}mu(d)g(dp_{i})$$
        $$= sum_{i = 1}^{k}sum_{d = 1}^{lfloor{frac{min(n, m)}{p_{i}}} floor}mu(d)lfloor{frac{n}{dp_{i}} floor lfloor{frac{m}{dp_{i}} floor}}$$<---枚举每个$mu(d)分别被每个质数统计了几次$
        $$= sum_{T = 1}^{min(n, m)} lfloor{frac{n}{T}} floor lfloor{frac{m}{T}} floorsum_{k|T}{mu(frac{T}{k})}$$<---枚举每个$lfloor{frac{n}{T}} floor lfloor{frac{m}{T}} floor$会给哪些$mu$做贡献(哪些$mu$会在某次被统计$lfloor{frac{n}{T}} floor lfloor{frac{m}{T}} floor$次)
        然后暴力枚举质数和系数,给对应的$mu$做贡献(质数$p_{i}$给它的倍数做贡献),统计前缀和,对前面的$lfloor{frac{n}{T}} floor lfloor{frac{m}{T}} floor$进行整数分块处理

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define R register int
     4 #define AC 10000100
     5 #define LL long long 
     6 int n, m, tot, t;
     7 int prime[AC], mu[AC];
     8 LL s[AC], ans;
     9 bool z[AC];
    10 
    11 inline int read()
    12 {
    13     int x = 0;char c = getchar();
    14     while(c > '9' || c < '0') c = getchar();
    15     while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    16     return x;
    17 }
    18 
    19 void pre()
    20 {
    21     int now;
    22     mu[1] = 1;
    23     for(R i = 2; i <= 10000000; i++)
    24     {
    25         if(!z[i]) prime[++tot] = i, mu[i] = -1;
    26         for(R j = 1; j <= tot; j++)
    27         {
    28             now = prime[j];
    29             if(i * now > 10000000) break;
    30             z[i * now] = true;
    31             if(!(i % now)) break;            
    32             mu[now * i] = -mu[i];
    33         }
    34     }
    35     int p;
    36     for(R i = 1; i <= tot; i++)//枚举质数 
    37     {
    38         p = prime[i];//卡常
    39         for(R j = p; j <= 10000000; j += p) //枚举倍数
    40             s[j] += mu[j / p];//or j = 系数, s[j * prime[i]] += mu[j];
    41     }
    42     for(R i = 1; i <= 10000000; i++) s[i] += s[i - 1];
    43 }
    44 
    45 void work()
    46 {
    47     t = read();
    48     while(t--)
    49     {
    50         int pos = 0;
    51         ans = 0;
    52         n = read(), m = read();
    53         int b = min(n, m);//这里要取min!!!
    54         for(R i = 1; i <= b; i = pos + 1)
    55         {
    56             pos = min(n / (n / i), m / (m / i));
    57             ans += (LL) (n / i) * (LL) (m / i) * (LL) (s[pos] - s[i - 1]);//error 只有ans是LL是不够的
    58         }        
    59         printf("%lld
    ", ans);
    60     }
    61 }
    62 
    63 int main()
    64 {
    65 //    freopen("in.in", "r", stdin);
    66     //freopen("YYnoGCD.in", "r", stdin);
    67     //freopen("YYnoGCD.out", "w", stdout);
    68     pre();
    69     work();
    70     //fclose(stdin);
    71     //fclose(stdout);
    72     return 0;
    73 }
  • 相关阅读:
    c语言练习24——数列求和
    Excel 常用属性的一小部分
    常见问题一之拼接表格 js传递参数变量 Json接收值
    关于下拉列表HtmlDownlistFor的使用
    Quay 基础版安装和部署
    Prometheus使用blackbox_exporter监控端口及网站状态(七)
    在CentOS 8上安装PostgreSQL 13 | RHEL 8
    nfs配置以及No route to host解决
    LNMP分离安装
    Linux配置和管理设备映射多路径multipath
  • 原文地址:https://www.cnblogs.com/ww3113306/p/9486079.html
Copyright © 2011-2022 走看看