zoukankan      html  css  js  c++  java
  • 【poj2773】 Happy 2006

    http://poj.org/problem?id=2773 (题目链接)

    题意

      给出两个数m,k,要求求出从1开始与m互质的第k个数。

    Solution

      数据范围很大,直接模拟显然是不行的,我们需要用到一些奇奇怪怪的方法。

      考虑是否可以通过某些途径快速得到解,然而并没有头绪。正难则反,能不能通过计算不与m互质的数的个数来得到互质的数的个数呢?答案是可行的,我们可以运用容斥。

      二分一个答案mid,容斥统计出在区间[1,mid]中是m的质因子的倍数的数的个数ans,然后我们可以用mid-ans得到区间中有多少个与m互质的数,不断二分下去,直到得出答案。 

      容斥统计的经典应用。

    代码

    // poj2773
    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #define LL long long
    #define MOD 10000
    #define inf 2147483640
    #define Pi acos(-1.0)
    #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
    using namespace std;
     
    const int maxn=100010;
    int vis[maxn],m,p[maxn],a[maxn];
    LL n,K,mid,ans;
    
    void dfs(int x,int y,int z) {
    	if (x==m+1) {
    		if (y!=0) {
    			if (y&1) ans+=mid/z;
    			else ans-=mid/z;
    		}
    		return;
    	}
    	dfs(x+1,y,z);
    	if ((double)z*a[x]<=mid) dfs(x+1,y+1,z*a[x]);
    }
    int main() {
    	for (int i=2;i<=2000;i++) if (!vis[i]) {
    			for (int j=i+i;j<=2000;j+=i) vis[j]=1;
    			p[++p[0]]=i;
    		}
    	while (scanf("%lld%lld",&n,&K)!=EOF) {
    		m=0;
    		for (int i=1;i<=p[0];i++) if (n%p[i]==0) {
    				while (n%p[i]==0) n/=p[i];
    				a[++m]=p[i];
    			}
    		if (n>1) a[++m]=n;
    		LL l=1,r=1e18,res=0;
    		while (l<=r) {
    			mid=(l+r)>>1;
    			ans=0;dfs(1,0,1);
    			if (mid-ans>=K) res=mid,r=mid-1;
    			else l=mid+1;
    		}
    		printf("%lld
    ",res);
    	}
        return 0;
    }
    

      

      

    This passage is made by MashiroSky.
  • 相关阅读:
    Vasya and Endless Credits CodeForces
    Dreamoon and Strings CodeForces
    Online Meeting CodeForces
    数塔取数 基础dp
    1001 数组中和等于K的数对 1090 3个数和为0
    1091 线段的重叠
    51nod 最小周长
    走格子 51nod
    1289 大鱼吃小鱼
    POJ 1979 Red and Black
  • 原文地址:https://www.cnblogs.com/MashiroSky/p/5913989.html
Copyright © 2011-2022 走看看