1. 程式人生 > >codeforces 839D (推公式+容斥原理/莫比烏斯函式)

codeforces 839D (推公式+容斥原理/莫比烏斯函式)

Winter is here at the North and the White Walkers are close. John Snow has an army consisting of n soldiers. While the rest of the world is fighting for the Iron Throne, he is going to get ready for the attack of the White Walkers.

He has created a method to know how strong his army is. Let the i-th soldier’s strength be ai. For some k he calls i1, i2, …, ik a clan if i1 < i2 < i3 < … < ik and gcd(ai1, ai2, …, aik) > 1 . He calls the strength of that clan k·gcd(ai1, ai2, …, aik). Then he defines the strength of his army by the sum of strengths of all possible clans.

Your task is to find the strength of his army. As the number may be very large, you have to print it modulo 1000000007 (109 + 7).

Greatest common divisor (gcd) of a sequence of integers is the maximum possible integer so that each element of the sequence is divisible by it.

Input
The first line contains integer n (1 ≤ n ≤ 200000) — the size of the army.

The second line contains n integers a1, a2, …, an (1 ≤ ai ≤ 1000000) — denoting the strengths of his soldiers.

Output
Print one integer — the strength of John Snow’s army modulo 1000000007 (109 + 7).

Example
Input
3
3 3 1
Output
12
Input
4
2 3 4 6
Output
39
Note
In the first sample the clans are {1}, {2}, {1, 2} so the answer will be 1·3 + 1·3 + 2·3 = 12

題意 就是讓你算所有gcd 的貢獻和,每個gcd的貢獻是所能產生該gcd的序列長度*gcd的和

讓你求總貢獻。

首先能想到的是求出產生gcd 為k的所有序列,也就是k的倍數的個數,然後在這些個數裡面任取
例如 gcd=2,有序列 2 4 6 那麼肯定是認取了也就是所有的集合*長度
得到公式 1*C(1,n)+2*C(2,n)+3*C(3,n)+…+n*C(n,n)
然後怎麼求這個的總和呢 可以發現 把係數和底相乘,然後再把分子提出第一個數n 就又變成了
n*C(0,n-1)+n*C(1,n-1)+n*C(2,n-1)+…..n*C(n-1,n-1) = n*2^n-1

但是還是有個小問題就是 當你算2的上述組合數的時候會把4 8的都算上,例如 2 4 8 4和8的gcd是4 所以然後算2的時候這裡要減去4和8的貢獻

兩種做法一種是莫比烏斯

#include <bits/stdc++.h>

const int N = 1000010;
typedef long long ll;
ll num[N+10],tong[N+10];
int a[N+10],vis[N+10];
using namespace std;
int cnt; 
const int mod = 1e9+7;
int maxx;
ll you[N];

int prime[N],mu[N];  



void Init(){    
    mu[1] = 1;  
    cnt = 0;  
    for(int i=2; i<N; i++){  
        if(!vis[i]){  
            prime[cnt++] = i;  
            mu[i] = -1;  
        }  
        for(int j=0; j<cnt&&i*prime[j]<N; j++){  
            vis[i*prime[j]] = 1;  
            if(i%prime[j]) mu[i*prime[j]] = -mu[i];  
            else{  
                mu[i*prime[j]] = 0;  
                break;  
            }  
        }  
    }
  }


ll qpow(ll a,ll b)
{
    ll res=1;
    while(b)
    {
        if(b&1) res=res*a,res%=mod;
        a*=a;
        a%=mod;
        b>>=1;
    }
    return res;
}

void init()
{

    for(int i=2;i<=maxx;i++)
    {
        tong[i]+=num[i];
        for(int j=i+i;j<=maxx;j+=i)
        {
            tong[i]+=num[j];
        }
        if(tong[i])
        tong[i]=tong[i]*qpow(2,tong[i]-1);
        tong[i]%=mod;
    }
}


long long ans;

int main()
{
    int n;
    Init();
    scanf("%d",&n);

    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        maxx=max(maxx,a[i]);
        num[a[i]]++;
    }
    init();

    for(int i=1;i<=maxx;i++)
    {
        if(tong[i]==0) continue;
        ll h=0;
        for(int j=i;j<=maxx;j+=i)
        {
            if(tong[j])
            h=(h+mu[j/i]*(tong[j])+mod)%mod;
        }
        ans=ans+(h*i)%mod;
        ans%=mod;
    }
    printf("%lld\n",ans);
}

一種是倒著容斥
其實是一樣的

#include <bits/stdc++.h>

const int N = 1000010;
typedef long long ll;
ll num[N+10],tong[N+10];
int a[N+10],vis[N+10];
using namespace std;
int cnt; 
const int mod = 1e9+7;
int maxx;
ll you[N];

ll qpow(ll a,ll b)
{
    ll res=1;
    while(b)
    {
        if(b&1) res=res*a,res%=mod;
        a*=a;
        a%=mod;
        b>>=1;
    }
    return res;
}

void init()
{

    for(int i=2;i<=maxx;i++)
    {
        tong[i]+=num[i];
        for(int j=i+i;j<=maxx;j+=i)
        {
            tong[i]+=num[j];
        }
        if(tong[i]==0) continue;
        you[i]=tong[i]*qpow(2,tong[i]-1);
        you[i]%=mod;
    }
}


long long ans;

int main()
{
    int n;
    scanf("%d",&n);

    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        maxx=max(maxx,a[i]);
        num[a[i]]++;
    }
    init();

    for(int i=maxx;i>=2;i--)
    {
        if(tong[i]==0) continue;
        for(int j=i+i;j<=maxx;j+=i)
        {
            you[i]=(you[i]-you[j]+mod)%mod;
        }
        ans=ans+(you[i]*i)%mod;
        ans%=mod;
    }
    printf("%lld\n",ans);
}