• 质因子和容斥原理


    算一个数字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;
    }
  • 相关阅读:
    java实现报数游戏
    java实现取字母组成串
    java实现取字母组成串
    java实现取字母组成串
    java实现取字母组成串
    java实现取字母组成串
    java实现填写算式
    java实现填写算式
    java实现填写算式
    java实现填写算式
  • 原文地址:https://www.cnblogs.com/luoyugongxi/p/12243962.html
Copyright © 2020-2023  润新知