1. 程式人生 > >組合數學-容斥原理-求指定區間內與n互素的數的個數

組合數學-容斥原理-求指定區間內與n互素的數的個數

求指定區間內與n互素的數的個數

給出整數n和r。求區間[1,r]中與n互素的數的個數。

去解決它的逆問題,求不與n互素的數的個數。

考慮n的所有素因子pi(i=1···k)

在[1,r]中有多少數能被pi整除呢?它就是

 

然而,如果我們單純將所有結果,會得到錯誤答案。有些數可能被統計了多次(被好幾素因子整除,如6,在計算2時,3時就重複了)

所以我們要用容斥原理來解決。我們可以用2^k的演算法求出所有的pi的組合,然後計算每種組合的pi乘積,通過容斥原理來對結果進行加減處理。

關於此問題的最終實現

int prim[maxn];
int solve(int n,int r)
{
    int num=0;
    for(int i=2;i<=sqrt(n);i++)
    {
        if(n%i==0)
        {
            prim[num++]=i;
            while(n%i==0)
                n/=i;
        }
    }
    if(n>1)
        prim[num++]=n;
    //對n分解素因子,num是n的素因子的個數
    int sum=0;
    for(int msk=1;msk<(1<<num);i++)
    {//(1<<sum)是一個長為num的二進位制,msk通過從1到(1<<num)迴圈可以列舉這個二進位制的每一種排列情況
      //msk<(1<<num)是把000··的這種排列去掉了,因為得選素因子
      //二進位制排列中1表示選n該位置的的素因子,0表示不選
  int mult=1;
        bits=0;
        for(int i=0;i<num;i++)
        {
            if((1<<i)&msk)//表示的是msk二進位制的第i位數字
            {
                bits++;
                mult*p[i];
            }
        }
        int cur=r/mult;
        if(bits&1)
            sum+=cur;
        else
            sum-=cur;
    }
    return r-sum;
}

比如n的素因子的個數num=6,msk=000001,表示只選擇了n的p[0]這個素因子

msk=011001,表示選擇了n的p[0],p[3],p[4],這三個素因子。

容斥定理可以用位運算和dfs來實現