lightOJ 1161 Extreme GCD(素數四元組)[容斥原理]

lightOJ 1161 Extreme GCD(素數四元組)[容斥原理]

鏈接:lightOJ 1161
在這裏插入圖片描述
題意:給你nn個數,選擇其中四個數作爲一組,使得這一組數的最大GCD爲11,問你有多少組?
題解:這裏用到容斥原理,先求逆問題,求GCD>1>1的個數,然後用總值減去這個值。首先預處理出來因子包含ii的數的個數,用num[i]num[i]預存。對於GCD=i=i的個數ans[i]=Cnum[i]4ans[i] = C_{num[i]}^4,對於預處理因子ii的時候,ii的因子也會被預處理,那麼在計算ii的因子jj的情況時,一定包含了ii的情況,所以對求GCD>1>1的個數的問題產生過一次貢獻,在求jj產生的貢獻時,需要將其倍數減去,以免重複計算。例如對於i=6,j=3i=6,j=3時,ans[3]=Cnum[3]4ans[6]ans[33]ans[3k]ans[3] = C_{num[3]}^4 -ans[6]-ans[3*3]-···-ans[3*k],逆向遞推,求到i=2i=2的時候,即是GCD>1>1的個數,分別存在ans[i]ans[i],然後用全部的減去這些值。即遞推到i=1i=1的情況(因爲每個數都包含因子11,所以num[1]=nnum[1]=n)
代碼:

#include<bits/stdc++.h>

using namespace std;
typedef long long LL;
const int maxn = 1e4+100;

int num[maxn];

void init_num(int x)
{
    for(int i = 1; i <= x/i;i++)
    {
        if(x%i==0)
        {
            if(i*i==x)
            {
                num[i]++;
            }
            else
            {
                num[i]++;
                num[x/i]++;
            }
        }
    }
    return ;
}

LL solve_C(int x)
{
    LL ans = x;
    ans = ans*(ans-1)*(ans-2)*(ans-3)/24;
    return ans;
}
LL ans[maxn];
int main()
{
    int t,cas = 0;
    scanf("%d", &t);
    while(t--)
    {
        int n,x;
        int ma = 0;
        scanf("%d", &n);
        for(int i = 0; i<= 10010; i++)
        {
            num[i] = 0;
            ans[i] = 0;
        }
        for(int i = 0; i < n; i++)
        {
            scanf("%d", &x);
            ma = max(ma,x);
            init_num(x);
        }
        for(int i = ma; i>=1;i--)
        {
            if(num[i]>=4)
            {
                ans[i] = solve_C(num[i]);
                for(int j = 2*i; j <= ma;j+=i)
                {
                    ans[i] -= ans[j];
                }
            }
        }
        printf("Case %d: %lld\n", ++cas,ans[1]);
    }



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