HDU 5212 Code (容斥 莫比烏斯反演基礎題)

_TCgogogo_發表於2015-09-06


Code

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)

Total Submission(s): 519    Accepted Submission(s): 206


Problem Description

WLD likes playing with codes.One day he is writing a function.Howerver,his computer breaks down because the function is too powerful.He is very sad.Can you help him?
The function:

int calc
{
  int res=0;
  for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
    {
      res+=gcd(a[i],a[j])*(gcd(a[i],a[j])-1);
      res%=10007;
    }
  return res;
}
 
Input
There are Multiple Cases.(At MOST10)
For each case:
The first line contains an integer N(1N10000).
The next line contains N integers a1,a2,...,aN(1ai10000).
 
Output
For each case:
Print an integer,denoting what the function returns.
 
Sample Input
5 1 3 4 2 4
 
Sample Output
64
Hint
gcd(x,y) means the greatest common divisor of x and y.
 
Source
BestCoder Round #39 ($)

題目連結:http://acm.hdu.edu.cn/showproblem.php?pid=5212

題目大意:就是求那個程式的值

題目分析:顯然n方會炸,因為ai最大才1e4,可以列舉gcd的值,但是計算的時候會重複,要容斥一下,這裡直接用莫比烏斯反演來容斥了


#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
using namespace std;
int const MAX = 10005;
int const MOD = 10007;
int mob[MAX], p[MAX], num[MAX], cnt[MAX]; //num表示i的倍數的個數,cnt表示i的個數
bool noprime[MAX];
int ma, n;

void Mobius()
{
    int pnum = 0;
    mob[1] = 1;
    for(int i = 2; i < MAX; i++)
    {
        if(!noprime[i])
        {
            p[pnum ++] = i;
            mob[i] = -1;
        }
        for(int j = 0; j < pnum && i * p[j] < MAX; j++)
        {
            noprime[i * p[j]] = true;
            if(i % p[j] == 0)
            {
                mob[i * p[j]] = 0;
                break;
            }
            mob[i * p[j]] = -mob[i];
        }
    }
}   

int cal()
{
    memset(num, 0, sizeof(num));
    for(int i = 1; i <= ma; i++)
        for(int j = i; j <= ma; j += i)
            num[i] += cnt[j];
    ll ans = 0;
    for(int i = 1; i <= ma; i++)
    {
        for(int j = i; j <= ma; j += i)
        {
            ll tmp = (ll) (num[j] * num[j] % MOD); //j的倍數的二元組數
            ans = (ans % MOD + (ll) mob[j / i] * tmp * i * (i - 1) % MOD + MOD) % MOD; //容斥
        }
    }
    return ans;
}

int main()
{
    Mobius();
    while(scanf("%d", &n) != EOF)
    {
        memset(cnt, 0, sizeof(cnt));
        int tmp;
        ma = 0;
        for(int i = 0; i < n; i++)
        {
            scanf("%d", &tmp);
            cnt[tmp] ++;
            ma = max(ma, tmp);
        }
        printf("%d\n", cal());
    }
}


相關文章