bzoj2005 [Noi2010]能量采集
Description
Input
仅包含一行,为两个整数n和m。
Output
仅包含一个整数,表示总共产生的能量损失。
Sample Input
5 4
【样例输入2】
3 4
Sample Output
36
【样例输出2】
20
对于100%的数据:1 ≤ n, m ≤ 100,000。
正解:莫比乌斯函数。
容易得出,题目要我们求的是$Ans=\sum_{i=1}^{n}\sum_{j=1}^{m}[2*(gcd(i,j)-1)+1]$。那么我们一堆乱搞就行了。
从而得到$Ans=2\sum_{i=1}^{n}\sum_{j=1}^{m}gcd(i,j)-n*m$。
$Ans=2\sum_{d=1}^{min(n,m)}d*\sum_{i=1}^{n}\sum_{j=1}^{m}[gcd(i,j)==d]-n*m$。
$Ans=2\sum_{d=1}^{min(n,m)}d*\sum_{i=1}^{\left \lfloor \frac{n}{d} \right \rfloor}\sum_{j=1}^{\left \lfloor \frac{m}{d} \right \rfloor}[gcd(i,j)==1]-n*m$。
$Ans=2\sum_{d=1}^{min(n,m)}d*\sum_{i=1}^{\left \lfloor \frac{n}{d} \right \rfloor}\sum_{j=1}^{\left \lfloor \frac{m}{d} \right \rfloor}\sum_{q|gcd(i,j)}\mu(q)-n*m$。
$Ans=2\sum_{d=1}^{min(n,m)}d*\sum_{q=1}^{min(\left \lfloor \frac{n}{d} \right \rfloor,\left \lfloor \frac{m}{d} \right \rfloor)}\mu(q)*\left \lfloor \frac{n}{dq}\right \rfloor\left \lfloor \frac{m}{dq} \right \rfloor-n*m$。
然后我们运用数论分块,可以将时间复杂度优化至$O(n\sqrt{n})$或$O(n)$。于是,这道题就被解决了。
1 //It is made by wfj_2048~ 2 #include <algorithm> 3 #include <iostream> 4 #include <cstring> 5 #include <cstdlib> 6 #include <cstdio> 7 #include <vector> 8 #include <cmath> 9 #include <queue> 10 #include <stack> 11 #include <map> 12 #include <set> 13 #define inf (1<<30) 14 #define N (100010) 15 #define il inline 16 #define RG register 17 #define ll long long 18 #define min(a,b) (a<b ? a : b) 19 #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout) 20 21 using namespace std; 22 23 int vis[N],mu[N],prime[N],n,m,nn,mm,cnt,pos1,pos2; 24 ll ans,anss; 25 26 il int gi(){ 27 RG int x=0,q=1; RG char ch=getchar(); while ((ch<'0' || ch>'9') && ch!='-') ch=getchar(); 28 if (ch=='-') q=-1,ch=getchar(); while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); return q*x; 29 } 30 31 il void sieve(){ 32 vis[1]=mu[1]=1; 33 for (RG int i=2;i<=m;++i){ 34 if (!vis[i]) vis[i]=1,mu[i]=-1,prime[++cnt]=i; 35 for (RG int j=1,k=i*prime[j];j<=cnt && k<=m;++j,k=i*prime[j]){ 36 vis[k]=1; if (i%prime[j]) mu[k]=-mu[i]; else{ mu[k]=0; break; } 37 } 38 } 39 for (RG int i=1;i<=m;++i) mu[i]+=mu[i-1]; return; 40 } 41 42 il void work(){ 43 n=gi(),m=gi(); if (n>m) swap(n,m); sieve(); 44 for (RG int d=1;d<=n;d=pos1+1){ 45 pos1=min(n/(n/d),m/(m/d)),nn=n/pos1,mm=m/pos1,anss=0; 46 for (RG int i=1;i<=nn;i=pos2+1){ 47 pos2=min(nn/(nn/i),mm/(mm/i)); 48 anss+=(ll)(nn/pos2)*(ll)(mm/pos2)*(ll)(mu[pos2]-mu[i-1]); 49 } 50 ans+=(ll)(d+pos1)*(ll)(pos1-d+1)/2*anss; 51 } 52 printf("%lld\n",2*ans-(ll)n*(ll)m); return; 53 } 54 55 int main(){ 56 File("energy"); 57 work(); 58 return 0; 59 }