zoukankan      html  css  js  c++  java
  • SPOJ-PGCD Primes in GCD Table

    题目链接:https://vjudge.net/problem/SPOJ-PGCD

    题目大意:

      给定 (N) 和 (M),求满足 ((1 le x le N), (1 le y le M)),且 (gcd(x,y)) 为素数的 ((x,y)) 的对数。

    知识点:  莫比乌斯反演

    解题思路:

      设 (g(p)) 表示满足 ((1 le x le N), (1 le y le M)),且 (gcd(x,y) = p) 的 ((x,y)) 的对数。直接求 (g(p)) 是不可行的,其时间复杂度为 (O(NM)).

      再设 (f(p)) 表示满足 ((1 le x le N), (1 le y le M)),且 (p|gcd(x,y)) 的 ((x,y)) 的对数,易知 (f(p)=(N/p)*(M/p))。且不难推出 (f(n) = sum limits_{n|d} g(d)).    ((1))

      莫比乌斯反演公式:若满足 (F(n) = sum limits_{n|d} f(d)),则有 (f(n) = sum limits_{n|d} mu(frac{d}{n})F(d)).

      将其代入式 ((1)) 得:

      (g(n) = sum limits_{n|d} mu(frac{d}{n})f(d) = sum limits_{n|d} mu(frac{d}{n})(N/d)(M/d))  ((2))

      最终的答案为((p) 代表质数):

      (sum limits_{p} g(p) = sum limits_{p} sum limits_{p|d} mu(frac{d}{p})(N/d)(M/d))

          (= sum limits_{d}^{min(M,N)} (N/d)(M/d) sum limits_{p|d} mu(frac{d}{p}))  ((3))

    第二个求和函数可以预处理,枚举每一个质数,更新对应的前缀和。

    AC代码:

     1 #include <bits/stdc++.h>
     2 
     3 using namespace std;
     4 typedef long long LL;
     5 const int maxn = 1e7+5;
     6 bool check[maxn];
     7 int prime[maxn],Mobius[maxn];
     8 int tot;
     9 int u[maxn];
    10 
    11 void init(){
    12     Mobius[1]=1;
    13     tot=0;
    14     for(int i=2;i<maxn;i++){
    15         if(!check[i]){
    16             prime[tot++]=i;
    17             Mobius[i]=-1;
    18         }
    19         for(int j=0;j<tot&&i*prime[j]<maxn;j++){
    20             check[i*prime[j]]=true;
    21             if(i%prime[j]==0){
    22                 Mobius[i*prime[j]]=0;
    23                 break;
    24             } else
    25                 Mobius[i*prime[j]]=-Mobius[i];
    26         }
    27     }
    28     for(int i=0;i<tot;i++){
    29         for(int j=prime[i];j<maxn;j+=prime[i]){
    30             u[j]+=Mobius[j/prime[i]];   // u[j] 代表分子为 j(对应式3中的d) 的和函数的值
    31         }
    32     }
    33     for(int i=1;i<maxn;i++) u[i]+=u[i-1];   //处理出前缀和
    34 }
    35 int main(){
    36     init();
    37     int t,n,m;
    38     scanf("%d",&t);
    39     while(t--){
    40         LL ans=0;
    41         int last;
    42         scanf("%d%d",&n,&m);
    43         for(int i=1;i<=min(n,m);i=last+1){
    44             last=min(n/(n/i),m/(m/i));  // [i,last] 这一段的 u[] 对应 (N/d)(M/d) 相等,不难用实验验证
    45             ans+=(LL)(n/i)*(m/i)*(u[last]-u[i-1]);
    46         }
    47         printf("%lld
    ",ans);
    48     }
    49     return 0;
    50 }

         

      

    “这些年我一直提醒自己一件事情,千万不要自己感动自己。大部分人看似的努力,不过是愚蠢导致的。什么熬夜看书到天亮,连续几天只睡几小时,多久没放假了,如果这些东西也值得夸耀,那么富士康流水线上任何一个人都比你努力多了。人难免天生有自怜的情绪,唯有时刻保持清醒,才能看清真正的价值在哪里。”
  • 相关阅读:
    实现带有头结点的链表
    数据结构之链式线性表
    HDU 1010 dfs+奇偶剪枝
    数据结构之顺序线性表
    POJ 1753 dfs+枚举
    HDU 4277 dfs+set去重
    平衡二叉树
    线性素数筛+欧拉线性筛(证明)
    dp--2019南昌网络赛B-Match Stick Game
    线段树+单调栈+前缀和--2019icpc南昌网络赛I
  • 原文地址:https://www.cnblogs.com/Blogggggg/p/8954320.html
Copyright © 2011-2022 走看看