BZOJ 2005: [Noi2010]能量采集(容斥+数论)
解题思路
首先题目要求的其实就是\(\sum\limits_{i=1}^n \sum\limits_{j=1}^m [(gcd(i,j)-1)*2+1)]\),然后变形可得\(-n*m+2\sum\limits_{i=1}^n \sum\limits_{j=1}^m gcd(i,j)\)。所以本质上是求后面那个式子,设\(f[i]\)表示\(i\)这个约数作为\(gcd\)的次数,然后转移时考虑容斥,\(n/i*m/i\)表示含有\(i\)这个约数的数字个数,再减去\(f[i*2],f[i*3]...\)这些\(gcd\)不为\(i\)的。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int MAXN = 100005;
typedef long long LL;
LL f[MAXN],ans;
int n,m;
int main(){
scanf("%d%d",&n,&m);if(n>m) swap(n,m);
for(int i=n;i;i--){
f[i]=(LL)(n/i)*(m/i);
for(int j=(i<<1);j<=n;j+=i)
f[i]-=f[j];
ans+=f[i]*i;
}
printf("%lld",ans*2-(LL)n*m);
return 0;
}