1. 程式人生 > >BZOJ 2005: [Noi2010]能量採集(容斥+數論)

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;
}