1. 程式人生 > >容斥原理解決某個區間[1,n]閉區間與m互質數數量問題

容斥原理解決某個區間[1,n]閉區間與m互質數數量問題

除法 als tdi pla cin ack 二分 ans ||

首先貼出代碼(閉區間[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 "\n" 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 "\n"
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

容斥原理解決某個區間[1,n]閉區間與m互質數數量問題