嘘~ 正在从服务器偷取页面 . . .

hdu4135 Co-prime 题解


hdu4135 Co-prime 题解

题目链接:hdu4135 Co-prime

题意

\(T\) 组数据,每组给出 \(a,b,n\) ,求区间 \([a,b]\) 中有多少个数与 \(n\) 互质。

Given a number \(N\), you are asked to count the number of integers between \(A\) and \(B\) inclusive which are relatively prime to \(N\). Two integers are said to be co-prime or relatively prime if they have no common positive divisors other than \(1\) or, equivalently, if their greatest common divisor is \(1\). The number \(1\) is relatively prime to every integer.

\(1 \le a\le b\le 10^{15},~1 \le n \le 10^9\)

首先一个常见转化 \(\text{ans} = f(b)-f(a-1)\)

其中 \(f(k)\) 表示 \([1,k]\) 中与 \(n\) 互质的数的个数

注意到如果 \(x\)\(n=\prod\limits_{1\le i \le t} p_i^{k_i}\) 互质,

则对于任意 \(p_i\) ,均有 \(p_i \nmid x\)

直接去算并不好算,考虑容斥

下面会涉及一些定义,我放在了文章末尾

在这题里,“坏性质”就是与 \(p_i\) 不互质

我们 \(O(2^t)\) 枚举 \(S\) (显然 \(t \le \log n\)

举个例子,假设 \(S_i = \{1,2\}\)

则表示能放到 \(N(S)\) 中的一定要有 \(P_1,P_2\) 的性质

在这题里,就是能放到 \(N(S)\) 里的 \(x\) 满足 \(p_1 \mid x \,\land \, p_2 \mid x\)

时间复杂度为 \(O(Q\times 2^{t})\)

代码采用比较好理解的位运算写法

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iomanip>
#include <random>
#include <queue>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define N (int)(25)

int pcnt,p[N];
void getp(int n)
{
    pcnt=0;
    for(int i=2; i<=n/i; i++)
    {
        if(n%i==0) p[++pcnt]=i;
        while(n%i==0) n/=i;
    }
    if(n>1) p[++pcnt]=n;
}
int solve(int m)
{
    int ans=m;
    for(int i=1; i<(1<<pcnt); i++)
    {
        int res=1,c=0;
        for(int j=0; j<pcnt; j++)
            if(i&(1ll<<j)) ++c,res*=p[j+1];
        if(c&1) ans-=m/res;
        else ans+=m/res;
    }
    return ans;
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    int Q,a,b,n;
    scanf("%lld",&Q);
    for(int t=1; t<=Q; t++)
    {
        scanf("%lld%lld%lld",&a,&b,&n); getp(n);
        printf("Case #%lld: %lld\n",t,solve(b)-solve(a-1));
    }
    return 0;
}

容斥原理(principle of inclusion-exclusion):令 \(X\) 为一个有限集合\(P_1, P_2,\dots , P_m\) 是一些性质的集合,对于任意 \(S \subseteq [m]\) ,即 \(S\subseteq \{1,2,\cdots,m\}\) ,定义 \(N(S) = \{x \in X \mid \forall i \in S : x \text{ has } P_i\}\) 。那么 \(X\)满足性质 \(P_{1\sim m}\) 的元素个数\[ \sum_{S \subseteq [m]} (-1)^{|S|+1} \left|N(S)\right| \] 如果是不满足任何一个性质的话,把指数中的 \(|S|+1\) 改成 \(|S|\) 即可。


特别地,对于任意的 \(S \subseteq [m]\)如果 \(N(S)\) 只和 \(S\) 的大小(即 \(|S|\) )有关,那么式子可以化简为 \[ \sum_{i=0}^{m} (-1)^{i+1} \binom{m}{i} N(i) \] 其中 \(N(i)\) 表示对于任意满足 \(S \subseteq [m],|S|=i\)\(N(S)\) 值。

如果是不满足任何一个性质的话,把指数中的 \(i+1\) 改成 \(i\) 即可。

容斥原理的常用技巧

  1. 定义一些“坏性质” \(P_1,\dots,P_m\)

  2. 找到对于每个 \(S\subseteq [m]\) 计算 \(N(S)\) 的方法

  3. 套用容斥原理计算不满足任何一个“坏性质”的元素个数

  4. 注意这里求的是不满足任何坏性质,因此用以下公式 \[ \sum_{S \subseteq [m]} (-1)^{|S|} \left|N(S)\right| \]


文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录