Coprime HDU - 5072 2014 Asia AnShan Regional Contest B (數學 容斥)

題目鏈接 https://vjudge.net/problem/HDU-5072

題目大意

給定數組aia_i求滿足以下兩個條件其中一個的三元組(a,b,c)(a,b,c)的數量 ps:(a,b,c)=(b,c,a)ps:(a,b,c)=(b,c,a)
1.(a,b)=1,(a,c)=1,(b,c)=1(a,b)=1,(a,c)=1,(b,c)=1
2.(a,b)1,(a,b)1,(b,c)1(a,b)\not =1,(a,b)\not=1,(b,c)\not=1

解題思路

一開始沒什麼思路,題目的要求很繁瑣,加上感覺像是容斥,就往容斥的一般思路,求滿足反題目條件的數量,然後用總數量減,對於題目要求的兩種情況,要考慮三個關係式,比較繁瑣。
因爲abc調換不影響計數,可以這樣構建反問題:
(a,b)=1,(a,c)1(a,b)=1,(a,c)\not =1這樣不管bc之間的關係,都是題目的反問題。
但是這樣必定會有兩個二元組存在相同的狀態((x,y)1(x,y)=1)( (x,y)\not=1 ||(x,y)=1),在計算過程中如果枚舉每一個數那就會算兩次,最後問題的答案就是: (n3)res2\binom{n}{3}-\frac {res}{2}

對於aia_i假如{ana_n}中有xx個數和aia_i互質,那麼和aia_igcd不爲11的數的數量就是nx1n-x-1

接下來就是在{ana_n}中求和{a_i}互質的數的數量了,這是一個經典的容斥模型:
可以轉化成求:總數減去 和ai{a_i}有公共因子的數

先對每個aia_i打一個num[i]num[i]的表,表示有num[i]num[i]個數有因子ii
然後對每個ai{a_i}唯一分解,由於這裏ai<1e5a_i<1e5這裏的質因子的數量最多不超過77個,然後容斥一下,奇減偶加

注意對resres產生貢獻的時候不能出現負數

#include <bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define ll long long
//#define int ll
#define debug cout<<"fuck"<<endl;
#define pb  push_back
#define endl '\n'
#define fi first
#define se second
#define db double
#define pii pair<int,int>
#define mp make_pair
const int mod=(int)1e9+7;
const int maxn=(int)1e5+5;
int n;
int a[maxn];
int cnt[maxn];
void init()
{
    memset(cnt,0,sizeof(cnt));

    for(int i=1;i<=n;i++)
    {
        for(int j=1;j*j<=a[i];j++)
        {
            if(a[i]%j==0)
            {
                cnt[j]++;
                if(j!=a[i]/j)cnt[a[i]/j]++;
            }
        }
    }
}
vector<int>v;
int solve(int x)
{
    v.clear();
    int xx=x;
    for(int i=2;i*i<=xx;i++)
    {
        if(xx%i==0)
        {
            v.pb(i);
            while(xx%i==0)
            {
                xx/=i;
            }
        }
    }
    if(xx>1)v.pb(xx);

    int sz=(int)v.size();
    int ret=n;
    for(int i=1;i<(1<<sz);i++)
    {
        int cc=0;
        int now=1;
        for(int j=0;j<sz;j++)
        {
            if(i&(1<<j))
            {
                now*=v[j];
                cc++;
            }
        }
        if(cc&1)ret-=cnt[now];
        else ret+=cnt[now];
    }
    return ret;
}
int t;
int main()
{
    IOS
    cin>>t;
    while(t--)
    {
        cin>>n;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
        }
        init();
        ll res=(ll)n*(n-1)*(n-2)/6;
        ll sum=0;
        for(int i=1;i<=n;i++)
        {
            int num1=solve(a[i]);
            //cout<<num1<<endl;
            int num2=max(0,n-num1-1);
            sum+=(ll)num1*num2;
        }
        cout<<res-sum/2<<endl;
    }





    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章