质因子和容斥原理

算一个数字m,1~n之间有多少个与n互质的数

把n的素因子提取,进行二进制枚举,容斥

模板如下

il void pan(ll k){
    cnt=0;
    ll kk=sqrt(k);
    for(ll i=2;i<=kk;i++){
        if(k%i==0){
            s[cnt++]=i;
            while(k%i==0){k/=i;}
        }
    }
    if(k!=1){
        s[cnt++]=k;
    }
    return;
}
ll all(ll k){
    ll ans=0;
    for(ll i=1;i<((ll)1<<cnt);i++){
        ll sum=1,num1=0,tmp;
        for(ll j=0;j<cnt;j++){
            if(i&((ll)1<<j)){
                sum*=s[j];num1++;
            }
        }
        tmp=k/sum;
        if(num1&1){ans+=tmp;}
        else{
            ans-=tmp;
        }
    }
    return k-ans;
}

hdu4135

题意:输入n,m,k,在区间n~m中有多少跟k互质的数

思路:就是模板。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define il inline
#define it register int
#define lowbit(x) (x)&(-x)
#define mem(a,b) memset(a,b,sizeof(a))
#define mod 1000000007
const int maxn=1e5+10;
ll n,m,k2;
int t;
int cnt;
ll s[100];
il void pan(ll k){
    cnt=0;
    ll kk=sqrt(k);
    for(ll i=2;i<=kk;i++){
        if(k%i==0){
            s[cnt++]=i;
            while(k%i==0){k/=i;}
        }
    }
    if(k!=1){
        s[cnt++]=k;
    }
    return;
}
ll all(ll k){
    ll ans=0;
    for(ll i=1;i<((ll)1<<cnt);i++){
        ll sum=1,num1=0,tmp=i;
        for(ll j=0;j<cnt;j++){
            if(i&((ll)1<<j)){
                sum*=s[j];num1++;
            }
        }
        tmp=k/sum;
        if(num1&1){ans+=tmp;}
        else{
            ans-=tmp;
        }
    }
    return k-ans;
}
int main(){
    it cc=1;
    scanf("%d",&t);
    while(t--){
        scanf("%lld%lld%lld",&n,&m,&k2);
        pan(k2);//cout<<all(2)<<endl;
        printf("Case #%d: %lld
",cc++,all(m)-all(n-(ll)1));
    }
    return 0;
}

cf一道D题

题意:输入n,m,gcd(n,m)=gcd(n+x,m)的x有多少个,x的范围是0~m-1

思路:k=gcd(n,m),n=k*a1,m=k*a2,n+x=k*a3

a1,a2,a3必定互质

就是求 n/k ~ (n+m-1)/k之中有多少跟 m/k 互质的数

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define il inline
#define it register int
#define lowbit(x) (x)&(-x)
#define mem(a,b) memset(a,b,sizeof(a))
#define mod 1000000007
const int maxn=1e5+10;
ll n,m;
int t;
int cnt;
ll s[100];
il void pan(ll k){
    cnt=0;
    ll kk=sqrt(k);
    for(ll i=2;i<=kk;i++){
        if(k%i==0){
            s[cnt++]=i;
            while(k%i==0){k/=i;}
        }
    }
    if(k!=1){
        s[cnt++]=k;
    }
    return;
}
ll all(ll k){
    ll ans=0;
    for(ll i=1;i<((ll)1<<cnt);i++){
        ll sum=1,num1=0,tmp=i;
        for(ll j=0;j<cnt;j++){
            if(i&((ll)1<<j)){
                sum*=s[j];num1++;
            }
        }
        tmp=k/sum;
        if(num1&1){ans+=tmp;}
        else{
            ans-=tmp;
        }
    }
    return ans;
}
int main(){
    scanf("%d",&t);
    while(t--){
        scanf("%lld%lld",&n,&m);
        ll k0=__gcd(n,m);
        ll k1=n/k0;
        ll k2=m/k0;//cout<<k1<<k2<<endl;
        pan(k2);
        printf("%lld
",k2-all(k2+k1-(ll)1)+all(k1-(ll)1));
    }
    return 0;
}

欧拉函数 φ(n)  是小于等于 n 且与  n 互素的正整数的个数

n=p1^a1*p2^a2…pk^ak (p是质素)
 
就有 φ(n)=n*( 1 - 1/p1 )*( 1 - 1/p2 )…( 1 - 1/pk)
 
 
upd:
看了别人的博客,发现 D 题居然就是欧拉函数模板,好神奇.jpg!!!

让我好好想想

 upd2:
n~n+m-1%m等效于0~m-1,就是求欧拉函数
 
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define il inline
#define it register int
#define lowbit(x) (x)&(-x)
#define mem(a,b) memset(a,b,sizeof(a))
#define mod 1000000007
const int maxn=2e5+10;
ll n,t,m;
int main(){
    scanf("%lld",&t);
    while(t--){
        scanf("%lld%lld",&n,&m);
        ll k=__gcd(n,m);
        n/=k,m/=k;
        ll ans=m;
        for(ll i=2;i*i<=m;i++){
            if(m%i==0){
                while(m%i==0){m/=i;}
                ans=ans/i*(i-1);
            }
        }
        if(m!=1){
            ans=ans/m*(m-1);
        }
        printf("%lld
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/luoyugongxi/p/12243962.html