1. 程式人生 > >nyoj 第k個互質數(二分+容斥原理)

nyoj 第k個互質數(二分+容斥原理)

第k個互質數
描述 兩個數的a,b的gcd為1,即a,b互質,現在給你一個數m,你知道與它互質的第k個數是多少嗎?與m互質的數按照升序排列。
輸入
輸入m ,k (1<=m<=1000000;1<=k<=100000000)
輸出
輸出第k個數。
樣例輸入
10 1
10 2
10 3
樣例輸出
1
3
7

思路: 首先要知道,     在[1,m]之間與m互質的數的個數=[1,m]之間的總個數-[1,m]之間與n不互質的數的個數 所以,要先對m進行質因數分解,求出m有哪些質因數,然後二分列舉答案mid,用容斥求[1,mid]內與m互質的數有多少個,讓其結果與k比較 判斷的時候,[1,mid]之間與m互質的數的數量 = mid - (包含一個質因子的數的個數)+(包含2個質因子的數的個數)-(包含3個質因子的數的個數)+(包含4個質因子的數的個數).....
程式碼:
#include<stdio.h>
#include<vector>
using namespace std;

vector<int>a;//a來儲存m的質因子
int b[100];

void div(int m)
{
    for(int i=2;i*i<=m;i++)
    {
        if(m%i==0)
            a.push_back(i);
        while(m%i==0)
            m/=i;
    }
    if(m>1)
        a.push_back(m);
}

int cont(int n)
{
    int g=0,sum=n;
    b[++g]=1;
    for(int i=0;i<a.size();i++)
    {
        int t=g;
        for(int j=1;j<=g;j++)
        {
            b[++t]=-1*a[i]*b[j];//偶數個質因子為正,奇數個質因子為負
            sum+=n/b[t];//計算[1,n]之間有多少數含有因子b[t]
        }
        g=t;
    }
    return sum;
}
//二分列舉答案mid,計算[1,mid]內有多少個數與m互質,並將其結果與k比較
int Binary_search(int m,int k)
{
    int le=1,ri=1000000000,mid;
    while(le<=ri)
    {
        mid=(le+ri)>>1;
        if(cont(mid)>=k)
            ri=mid-1;
        else
            le=mid+1;
    }
    return le;
}

int main()
{
    int m,k;
    while(~scanf("%d%d",&m,&k))
    {
        a.clear();
        div(m);
        printf("%d\n",Binary_search(m,k));
    }
    return 0;
}