现在的位置: 首页 > 综合 > 正文

【莫比乌斯函数】【poj 2773】Happy 2006

2017年04月21日 ⁄ 综合 ⁄ 共 2630字 ⁄ 字号 评论关闭

http://poj.org/problem?id=2773


求第k大与n互质的数,二分+莫比乌斯水过

据说裸用容斥原理可以0ms

对此我表示hehe


我的时间复杂度:O(n+qsqrt(n)logn)

下面的:O(n+qsqrt(n)+qlogn*(2^(logn)))(如果同样是线性筛)

尼玛这根本不是多项式的复杂度啊。

【update】我x我犯逗了2^logn肿么不是多项式。。。。。。?

//#define _TEST _TEST
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
/************************************************
Code By willinglive    Blog:http://willinglive.cf
************************************************/
#define rep(i,l,r) for(int i=(l),___t=(r);i<=___t;i++)
#define per(i,r,l) for(int i=(r),___t=(l);i>=___t;i--)
#define MS(arr,x) memset(arr,x,sizeof(arr))
#define LL long long
#define INE(i,u,e) for(int i=head[u];~i;i=e[i].next)
inline const LL read()
{LL r=0,k=1;char c=getchar();for(;c<'0'||c>'9';c=getchar())if(c=='-')k=-1;
for(;c>='0'&&c<='9';c=getchar())r=r*10+c-'0';return k*r;}
/////////////////////////////////////////////////
const int N=1000000;
int prim[100000],mu[N+10],cnt;
bool flag[N+10];
int n,k,sq;
int a[2000];
/////////////////////////////////////////////////
void init_prim_mu()
{
	mu[1]=1;
	rep(i,2,N)
	{
		if(!flag[i]) prim[++cnt]=i,mu[i]=-1;
		for(int j=1;j<=cnt && i*prim[j]<=N;j++)
		{
			flag[i*prim[j]]=1;
			if(i%prim[j]==0)
			{
				mu[i*prim[j]]=0;
				break;
			}
			else mu[i*prim[j]]=-mu[i];
		}
	}
}
int cal(int x)
{
	int res=0;
	rep(i,1,*a)
	{
		res+=x/a[i]*mu[a[i]];
	}
	return res;
}
/////////////////////////////////////////////////
void solve()
{
	init_prim_mu();
	while(~scanf("%d%d",&n,&k))
	{
		int l=1,r=1000000000,mid;
		sq=(int)sqrt((double)n);
		*a=0;
		rep(d,1,sq) if(n%d==0)
		{
			a[++*a]=d;
			if(d*d!=n) a[++*a]=n/d;
		}
		while(l<r)
		{
			mid=l+r>>1;
			if(cal(mid)<k) l=mid+1;
			else r=mid;
		}
		printf("%d\n",l);
	}
}
/////////////////////////////////////////////////
int main()
{
    #ifndef _TEST
    freopen("std.in","r",stdin); freopen("std.out","w",stdout);
    #endif
    solve();
    return 0;
}

贴上神奇的裸容斥原理

From:http://blog.163.com/happyliyifan@126/blog/static/37462772201311315033520/

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <cmath>
#include <algorithm>
#define N 1005
using namespace std;
int n , k, K, cnt;
int mark[N + 10], prime[N];
int a[11];

void init()
{
    cnt = 0;
    for(int i = 2; i <= N; i++)
    {
        if(!mark[i])
        {
            prime[cnt++] = i;
            for(int j = 2 * i; j <= N; j += i)
            {
                mark[j] = 1;
            }
        }
    }
}

void getprime()
{
    int tmp = n;
    k = 0;
    for(int i = 0; i < cnt && prime[i] * prime[i] <= n; i++)
    {
        if(tmp % prime[i] == 0)
        {
            a[k++] = prime[i];
            while(tmp % prime[i] == 0)
            {
                tmp /= prime[i];
            }
        }
    }
    if(tmp != 1)
    {
        a[k++] = tmp;
    }
}

int judge(int num)
{
    int sum = 0;
    for(int i = 1; i < (1 << k); i++)
    {
        int tmp = 1;
        int t = 0;
        for(int j = 0; j < k; j++)
        {
            if((1 << j) & i)
            {
                t++;
                tmp = tmp * a[j];
            }
        }
        if(t % 2 == 1)
        {
            sum += num / tmp;
        }
        else
        {
            sum -= num / tmp;
        }
    }
    return num - sum;
}

int main()
{
    init();
    while(scanf("%d%d", &n, &K) != -1)
    {
        getprime();
        int l = 1, r = 1000000000, mid, ans;
        while(l <= r)
        {
            mid = (l + r) >> 1;
            int pt = judge(mid);
            if(pt >= K)
            {
                if(pt == K) ans = mid;
                r = mid - 1;
            }
            else
            {
                l = mid + 1;
            }
        }
        printf("%d\n", ans);
    }
}

抱歉!评论已关闭.