容斥原理专题

hdoj1796

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define int ll
const int N=20+10;
int n,m;
int a[20];
int gcd(int x,int y){
    return x%y?gcd(y,x%y):y;
}
signed main(){
    int T,x,y;
    while (scanf("%lld%lld",&n,&m)==2){
        n--;
        for (int i=0;i<m;i++){
            scanf("%lld",&a[i]);
            if (a[i]==0)i--,m--;
        }
        int ans=0;
        for (int i=1;i<(1<<m);i++){
            int p=1,cnt=0;
            for (int j=0;j<m;j++){
                if ((1<<j)&i){
                    p*=a[j]/gcd(p,a[j]);
                    cnt++;
                }
            }
            if (cnt&1)ans+=n/p;
            else ans-=n/p;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

hdoj2204

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define int ll
const int N=70+10;
int n,m;
int vis[N],prim[N];	
void euler(int n){
    int num=0;
    for (int i=2;i<=n;i++){
        if (vis[i]==0)prim[++num]=i;
        for (int j=1;j<=num&&prim[j]*i<=n;j++){
            vis[i*prim[j]]=1; 
            if (i%prim[j]==0)break;
        }
    }
}
int ans;
void dfs(int pre,int num,int cnt){
    for(int i=pre;;i++){
        int p=pow(n,1.0/num/prim[i])-1;
        if (!p)break;
        if (cnt&1)ans+=p;
        else ans-=p;
        dfs(i+1,num*prim[i],cnt+1);
    }
}
signed main(){
    int T,x,y;
    euler(70);
    while (scanf("%lld",&n)==1){
        ans=1;
        dfs(1,1,1);
        printf("%lld\n",ans);
    }
    return 0;
}

hdoj3388

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define int ll
const int N=70+10;
int n,m,cnt;
int a[N];
int ans;
void dfs(int k,int num,int s,int n){
    if (k==cnt+1){
        if (num&1)ans-=n/s;
        else ans+=n/s;//当num为0时为整体
        return;
    }
    dfs(k+1,num,s,n);
    dfs(k+1,num+1,s*a[k],n);
}
signed main(){
    int T,x,y,k;
    scanf("%lld",&T);
    for (int cas=1;cas<=T;cas++){
        scanf("%lld%lld%lld",&x,&y,&k);
        cnt=0;
        int t=max(x,y);
        for (int i=2;i*i<=t;i++){
            if (x%i==0||y%i==0)a[++cnt]=i;
            while (x%i==0)x/=i;
            while (y%i==0)y/=i;
        }
        if (x>1)a[++cnt]=x;if (y>1&&x!=y)a[++cnt]=y;
        int l=1,r=1e16;
        while (l<=r){
            int mid=(l+r)>>1;
            ans=0;
            dfs(1,0,1,mid);
            if (ans<k)l=mid+1;
            else r=mid-1;
        }
        printf("Case %lld: %lld\n",cas,l);
    }
    return 0;
}

hdoj1695

x a~b,y c~d gcd(x,y)=k的个数,因为(1,5)(5,1)被认为相同,所以要去重,注意(k,k)只有1组或0组

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N=1e6+10;
int n,m,k;
int mu[N],vis[N],prim[N],sum[N];
void get_mu(int n){
    int cnt=0; 
    mu[1]=1;
    for(int i=2;i<=n;i++){
        if(!vis[i]){prim[++cnt]=i;mu[i]=-1;}
        for(int j=1;j<=cnt&&prim[j]*i<=n;j++){
            vis[prim[j]*i]=1;
            if(i%prim[j]==0)break;
            else mu[i*prim[j]]=-mu[i];
        }
    }
    for(int i=1;i<=n;i++)sum[i]=sum[i-1]+mu[i];
}
ll S(int n,int m){
    n/=k;m/=k;
    if (n>m)swap(n,m);
    ll ans1=0,ans2=0;
    for(int l=1,r;l<=n;l=r+1){
        r=min(n/(n/l),m/(m/l));
        ans1+=1ll*(sum[r]-sum[l-1])*(n/l)*(m/l);
    }
    for(int l=1,r;l<=n;l=r+1){
        r=n/(n/l);
        ans2+=1ll*(sum[r]-sum[l-1])*(n/l)*(n/l);
    }
    return ans1-ans2/2;
}
int main(){
    int T,a,b,c,d;
    get_mu(N-1);
    scanf("%d",&T);
    for (int cas=1;cas<=T;cas++){
        scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
        if (k==0){
            printf("Case %d: 0\n",cas);
            continue;
        }
        printf("Case %d: %lld\n",cas,S(b,d)+S(a-1,c-1)-S(a-1,d)-S(b,c-1));
    }
    return 0;
}

hdoj4135

n~m内与k互质的数的个数

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N=30+10;
ll n,m;
int k,cnt;
int prim[N];
ll calc(ll n){
    ll ans=0;
    for(int i=1;i<(1<<cnt);i++){
        int tmp=1,r=0;
        for(int j=0;j<cnt;j++){
            if(((i>>j)&1)==0)continue;
            r++;tmp*=prim[j];
        }
        if(r&1)ans+=n/tmp;
        else ans-=n/tmp;
    }
    return n-ans;
}
int main(){
    int T,a,b,c,d;
    scanf("%d",&T);
    for (int cas=1;cas<=T;cas++){
        scanf("%lld%lld%d",&n,&m,&k);
        cnt=0;
        for (int i=2;i*i<=k;i++){
            if (k%i==0)prim[cnt++]=i;
            while (k%i==0)k/=i;
        }
        if (k>1)prim[cnt++]=k;
        printf("Case #%d: %lld\n",cas,calc(m)-calc(n-1));
    }
    return 0;
}

hdoj5514

有n青蛙,m个绕成圈的台阶,0-m-1,每个青蛙有跳的距离,问能被跳到的台阶的下标和
法1:1-n与n互质的数的和为phi(n)*n/2
对于步长为x的求和来说,就是x∗(与m/x互素的数的和),然后枚举所有的可能的步长,求和
法2:容斥
详见https://blog.csdn.net/qingshui23/article/details/73091006

//法1
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N=1e4+10;
int n,m;
int a[N],p[N],vis[N],num[N];
int euler(int n){
    int ret=n;
    for(int i=2;i<=sqrt(n);i++){
        if(n%i==0){
            ret=ret/i*(i-1);
            while(n%i==0)n/=i;
        }
    }
    if(n>1)ret=ret/n*(n-1);
    return ret;
}
int gcd(int x,int y){
    return x%y?gcd(y,x%y):y;
}
int ck(int x){
    for(int i=1;i<=n;i++)
        if(x%a[i]==0)return 1;
    return 0;
}
signed main(){
    int T;
    scanf("%d",&T);
    for (int cas=1;cas<=T;cas++){
        scanf("%d%d",&n,&m);
        for (int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            a[i]=gcd(a[i],m);
        }
        ll ans=0;
        for (int i=1;i*i<=m;i++){
            if(m%i)continue;
            if (ck(i))ans+=(1ll*euler(m/i)*m)/2;
            if(i*i==m||i==1) continue;
            if (ck(m/i)) ans+=(1ll*euler(i)*m)/2;
        }
        printf("Case #%d: %lld\n",cas,ans);
    }
    return 0;
}
//法2
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
#define int ll
const int N=1e4+10;
int n,m;
int a[N],p[N],vis[N],num[N];
int gcd(int x,int y){
    return x%y?gcd(y,x%y):y;
}
signed main(){
    int T;
    scanf("%lld",&T);
    for (int cas=1;cas<=T;cas++){
        scanf("%lld%lld",&n,&m);
        memset(vis,0,sizeof vis);
        memset(num,0,sizeof num);
        for (int i=1;i<=n;i++)scanf("%lld",&a[i]);
        int cnt=0;
        for (int i=1;i*i<=m;i++){
            if (m%i==0){
                p[++cnt]=i;
                if (i*i!=m)p[++cnt]=m/i;
            }
        }
        sort(p+1,p+1+cnt);
        for (int i=1;i<=n;i++){
            int d=gcd(a[i],m);
            for (int j=1;j<=cnt;j++){
                if (p[j]%d==0)vis[j]=1;
            }
        }
        int ans=0;
        for (int i=1;i<=cnt;i++){
            if(vis[i]!=num[i]){
                int t=(m-1)/p[i];
                ans+=t*(t+1)/2*p[i]*(vis[i]-num[i]);
                for (int j=i+1;j<=cnt;j++){
                    if(p[j]%p[i]==0){
                        num[j]+=vis[i]-num[i];
                    }
                }
            }
        }
        printf("Case #%lld: %lld\n",cas,ans);
    }
    return 0;
}

hdoj5201

hdoj5297

hdoj6021

hdoj5155

hdoj5471

hdoj2841

hdoj5794

hdoj6053

hdoj5468

hdoj4790

posted @ 2020-08-24 12:51  Rynar  阅读(179)  评论(0)    收藏  举报