zoukankan      html  css  js  c++  java
  • 容斥原理解决某个区间[1,n]闭区间与m互质数数量问题

    首先贴出代码(闭区间[1,n]范围内和m互质的数)

    代码:

    int solve(II n,II m){
        vector<II>p;
        for(II i=2;i*i<=m;i++){
            if(m%i==0){
                p.push_back(i);
                while(m%i==0) m/=i;
            }
        }
        if(m>1) p.push_back(m); 
        II sz=p.size();
        LL sum=0;
        for(II i=1;i<(1<<sz);i++){
            II ct=0;
            LL mul=1;
            for(II j=0;j<sz;j++){
                if(i&(1<<j)){
                    ct++;
                    mul*=p[j];
                }
            }
            if(ct&1) sum+=n/mul;
            else sum-=n/mul;
        }
        return n-sum;
    }

    这里解释一下原理:首先假设m有x个不同的质因子,那么可以组成的因子数就是2^x-1种,然后10^18以内所有的数的质因子个数不会超过15个,所以2^15次方暴力枚举所有情况这个复杂度还是可取的。我们假设p1,p2,p3都是m的质因子,假设当前枚举的因子是p1*p2*p3那么n以内可以整除p1*p2*p3的数量就是n/(p1*p2*p3),但是这里考虑到一个会重复问题就是拥有奇数个质因数的因子的在n以内可以整除的数量已经包含了偶数个数量,但是偶数个的并不包含奇数个的,所以我们枚举的时候需要奇加偶减,这样我们算出来的ans是n以内和m不互质的数的数量,那么和m互质的数量就是n-ans。

    贴上一些可以用这个方法解决的练习题:

    HDU1695:这个题好像正解使用什么莫比乌斯反演,题目的意思是求[1,a],[1,b]有多少对数GCD(x,y)==k,但是(x,y)和(y,x)算一对,有一个定理如果GCD(x,y)==k ,则GCD(x/k,y/k)==1那么现在问题转化为求[1,a/k],[1,b/k]以内互质的数有多少对,现在我们要取minn=min(a/k,b/k),我们可以先求minn的欧拉函数的前缀和,然后再求minn+1到max(a/k,b/k)的数在[1,max(a/k.b/k)]以内所有与它互质的数的数量,然后把所有的加起来就可以了。

    代码:

     1 //Author: xiaowuga
     2 #include <bits/stdc++.h>
     3 using namespace std;
     4 #define inf 0x3f3f3f3f
     5 #define MAX INT_MAX
     6 #define mem(s,ch) memset(s,ch,sizeof(s))
     7 const long long N=100000; 
     8 const long long mod=1e9+7; 
     9 typedef long long LL;
    10 typedef int II;
    11 typedef unsigned long long ull;
    12 #define nc cout<<"nc"<<endl
    13 #define endl "
    "
    14 vector<LL>Euler;
    15 void init_Euler(II n){
    16     Euler.resize(n+1);
    17     Euler[0]=0;
    18     Euler[1]=1;
    19     for(LL i=2;i<n;i++) Euler[i]=i;
    20     for(LL i=2;i<n;i++){
    21         if(Euler[i]==i){
    22             for(LL j=i;j<n;j+=i)
    23                 Euler[j]=Euler[j]/i*(i-1);//先进行除法防止溢出
    24         }
    25     }
    26     for(II i=1;i<n;i++){
    27         Euler[i]+=Euler[i-1];
    28     }
    29 }
    30 int solve(II n,II m){
    31     vector<II>p;
    32     for(II i=2;i*i<=m;i++){
    33         if(m%i==0){
    34             p.push_back(i);
    35             while(m%i==0) m/=i;
    36         }
    37     }
    38     if(m>1) p.push_back(m); 
    39     II sz=p.size();
    40     LL sum=0;
    41     for(II i=1;i<(1<<sz);i++){
    42         II ct=0;
    43         LL mul=1;
    44         for(II j=0;j<sz;j++){
    45             if(i&(1<<j)){
    46                 ct++;
    47                 mul*=p[j];
    48             }
    49         }
    50         if(ct&1) sum+=n/mul;
    51         else sum-=n/mul;
    52     }
    53     return n-sum;
    54 }
    55 int main() {
    56     ios::sync_with_stdio(false);cin.tie(0);
    57     II a,b,c,d,k;
    58     II T,ca=0;
    59     init_Euler(100000+1000);
    60     cin>>T;
    61     while(T--){
    62         cin>>a>>b>>c>>d>>k;
    63         if(k==0||k>b||k>d){
    64             cout<<"Case "<<++ca<<": "<<0<<endl;
    65             continue;
    66         } 
    67         if(b>d) swap(b,d);
    68         b/=k;d/=k;
    69         LL ans=Euler[b];
    70         for(II i=b+1;i<=d;i++){
    71             ans+=solve(b,i);
    72         }
    73         cout<<"Case "<<++ca<<": "<<ans<<endl;
    74     }
    75     return 0;
    76 }
    View Code

    POJ2773:这个题求第n个与k互质的数。

    1.一个简单的思路就是如果[1,k]中有x个与k互质的数,那么[k+1,2*k]中也有x个,每个k个一个循环都会出现x个数与k互质,而且加入y<k且y与k互质,则t*k+y也与k互质。那么我们第一个方法可以暴力算出比k小的数里面所有与k互质的数都是多少复杂度是klog(k),然后看一下n是k第几轮循环里面。然后直接确定这个数多少。

    2.二分+验证的思想,首先一个数越大,那么他包含的与k互质的数一定越多对吧?这个性质不就是单调性吗?任何满足单调性的问题我们都可以用二分来解决,所以我们可以用二分,加验证的思想找到和第n个k互质的数是多少

    代码:

     1 //Author: xiaowuga
     2 #include<iostream>
     3 #include<vector>
     4 using namespace std;
     5 #define inf 0x3f3f3f3f
     6 #define MAX INT_MAX
     7 #define mem(s,ch) memset(s,ch,sizeof(s))
     8 const long long N=100000; 
     9 const long long mod=1e9+7; 
    10 typedef long long LL;
    11 typedef int II;
    12 typedef unsigned long long ull;
    13 #define nc cout<<"nc"<<endl
    14 #define endl "
    "
    15 LL solve(II r,LL n){
    16     vector<int>p;
    17     for(II i=2;i*i<=r;i++){
    18         if(r%i==0){
    19             p.push_back(i);
    20             while(r%i==0) r/=i;
    21         }
    22     }
    23     if(r>1) p.push_back(r);
    24     LL sum=0;
    25     for(LL i=1;i<(1<<p.size());i++){
    26         LL d=1,ct=0;
    27         for(II j=0;j<p.size();j++){
    28             if(i&(1<<j)){
    29                 ct++;
    30                 d*=p[j];
    31             }
    32         }
    33         if(ct%2) sum+=n/d;
    34         else sum-=n/d;
    35     }
    36     return n-sum;
    37 }
    38 int main() {
    39     ios::sync_with_stdio(false);cin.tie(0);
    40     II n,k;
    41     while(cin>>n>>k){
    42         LL l=1,r=inf*2;
    43         LL ans=1;
    44         while(l<r){
    45             LL m=l+(r-l)/2;
    46             LL t=solve(n,m);
    47             if(t>=k){
    48                if(t==k) ans=m;  
    49                r=m; 
    50             }
    51             else{
    52                 l=m+1;
    53             }
    54         }
    55         cout<<ans<<endl;
    56     }
    57     return 0;
    58 }
    View Code
  • 相关阅读:
    sniffer 和 debug flow
    如何认识TOS----DSCP 对照表
    NAT alg 和 ASPF
    使用refind引导多系统
    Backdooring a OS VM
    exit(0)与exit(1),return三者区别(详解)
    Codeforces Round #301 (Div. 2)(A,【模拟】B,【贪心构造】C,【DFS】)
    2017年中国大学生程序设计竞赛-中南地区赛暨第八届湘潭市大学生计算机程序设计大赛题解&源码(A.高斯消元,D,模拟,E,前缀和,F,LCS,H,Prim算法,I,胡搞,J,树状数组)
    高斯消元法(Gauss Elimination)【超详解&模板】
    2015 计蒜之道 初赛(4)爱奇艺的自制节目(枚举 贪心)
  • 原文地址:https://www.cnblogs.com/xiaowuga/p/7631291.html
Copyright © 2011-2022 走看看