zoukankan      html  css  js  c++  java
  • BZOJ 2005: [Noi2010]能量采集(莫比乌斯反演)

    http://www.lydsy.com/JudgeOnline/problem.php?id=2005

    题意:

     
    思路:
    首先要知道一点是,某个坐标(x,y)与(0,0)之间的整数点的个数为gcd(x,y),这样一来每个坐标损失的能量为2*gcd(x,y)-1。
    所以在这道题目中要计算的就是
     
    f(d)表示gcd(x,y)=d的对数,那么F(d)表示d|gcd(x,y)的对数。
    根据反演可以得到,
    那么这道题的答案就是,
     1 #include<iostream>
     2 #include<algorithm>
     3 #include<cstring>
     4 #include<cstdio>
     5 #include<sstream>
     6 #include<vector>
     7 #include<stack>
     8 #include<queue>
     9 #include<cmath>
    10 #include<map>
    11 #include<set>
    12 using namespace std;
    13 typedef long long ll;
    14 typedef pair<int,int> pll;
    15 const int INF = 0x3f3f3f3f;
    16 const int maxn = 100000 + 5;
    17 
    18 bool check[maxn];
    19 int prime[maxn];
    20 int mu[maxn];
    21 ll sum[maxn];
    22 
    23 void Mobius()
    24 {
    25     memset(check, false, sizeof(check));
    26     mu[1] = 1;
    27     int tot = 0;
    28     for (int i = 2; i <= maxn; i++)
    29     {
    30         if (!check[i])
    31         {
    32             prime[tot++] = i;
    33             mu[i] = -1;
    34         }
    35         for (int j = 0; j < tot; j++)
    36         {
    37             if (i * prime[j] > maxn)
    38             {
    39                 break;
    40             }
    41             check[i * prime[j]] = true;
    42             if (i % prime[j] == 0)
    43             {
    44                 mu[i * prime[j]] = 0;
    45                 break;
    46             }
    47             else
    48             {
    49                 mu[i * prime[j]] = -mu[i];
    50             }
    51         }
    52     }
    53     sum[0]=0;
    54     for(int i=1;i<maxn;i++)
    55         sum[i]=sum[i-1]+mu[i];
    56     return ;
    57 }
    58 
    59 ll solve(int n, int m)
    60 {
    61     if(n>m)  swap(n,m);
    62     ll tmp=0;
    63     for(int i=1,last=0;i<=n;i=last+1)
    64     {
    65         last=min(n/(n/i),m/(m/i));
    66         tmp+=(sum[last]-sum[i-1])*(n/i)*(m/i);
    67     }
    68     return tmp;
    69 }
    70 
    71 int n, m;
    72 
    73 int main()
    74 {
    75     //freopen("in.txt","r",stdin);
    76     Mobius();
    77     while(~scanf("%d%d",&m,&n))
    78     {
    79         ll ans=0;
    80         for(int i=1;i<=min(n,m);i++)   //枚举d
    81             ans+=solve(n/i,m/i)*i;     //这儿求gcd(x,y)=d的对数,但是如果/i的话就相当于计算gcd(x,y)=1的对数
    82                                        //简化了计算
    83         printf("%lld
    ",2*ans-(ll)n*m);
    84     }
    85     return 0;
    86 }
  • 相关阅读:
    QSetting
    类中函数前、后、参数加const
    delete指针
    自定义数组类
    手动调用构造函数
    windows和linux平台下的通用时间测试函数
    多线程编程学习
    Android 利用ImageView显示图片
    特征描述算子-sift
    opencv边界扩展
  • 原文地址:https://www.cnblogs.com/zyb993963526/p/7260554.html
Copyright © 2011-2022 走看看