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\n",2*ans-(ll)n*m);
84     }
85     return 0;
86 }

 

posted @ 2017-07-30 21:30  、苏州城外的微笑  阅读(...)  评论(...编辑  收藏