容斥原理 —— 求1~n有多少个数与k互质(二进制算法详细解释&模板)

void pr(int k)      //求k的质因子  
{  
    num = 0;  
    for (int i = 2 ; i * i <= k ; i++)  
    {  
        if (k % i == 0)  
        {  
            p[num++] = i;  
            while (k % i == 0)  
                k /= i;  
        }  
    }  
    if (k > 1)  
        p[num++] = k;  
}  

我们首先把k分解质因数,储存到p数组中,num表示质因子的数量。

然后用容斥原理,我们反着求不与k互质的数的个数,到时候一减就得出结果了。

举个例子,比如 k 的质因子有 2,3,5。那么2、3、5的倍数都不和 k 互质,另外还没有完,可能有重复的地方,比如6,既是2的倍数又是3的倍数,前面用 k/2 + k/3 的时候多减了,这个时候要加上 k / (2*3)。同理,10,15这一类数都应该加上。但是还有类似于30这样的数,它是2,3,5的倍数,减的时候又多减了。

然后我们会发现,出现奇数个数,就用加法,偶数个数用减法。

最后的式子是这样的:k / 2 + k / 3 + k / 5 - k / (2 * 3) - k / (3 * 5) - k / (2 * 5) + k / (2 * 3 * 5)

有点长,看一下容易发现我说的奇偶的规律。


但是要怎么取算这个又出现问题了。

这里提供二进制的方法,个人觉得比较好理解。

设质因数的个数为m。

有一个浮动的数字,从1 ~ m依次递增,它的二进制的每一位表示用了哪些数字,比如5(101),其二进制的第一位和第三位(倒着数)是1,则它表示用了第一个质因数和第三个质因数。就是这个意思,这样就能发现:从1到m遍历一遍,就把所有的可能都包括了。



代码:

__int64 solve(__int64 n)        //1~n中不与k互质的数   
{  
    __int64 ans = 0;  
    for (__int64 i = 1; i < (__int64)1 << num ; i++)       //其二进制位为1,表示这些质因数被用到   
    {  
        int ant = 0;        //用奇数个质因数加,偶数个减  
        __int64 t = 1;  
        for (int j = 0 ; j < num ; j++)  
        {  
            if (((__int64)1 << j) & i)  
            {  
                t *= p[j];  
                ant++;  
            }  
        }  
        if (ant & 1)        //奇数加  
            ans += n / t;  
        else        //偶数减   
            ans -= n / t;  
    }  
    return ans;  
}  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值