【XSY1580】Y队列 容斥

题目大意

  给你\(n,r\),求第\(n\)个不能被表示为\(a^b(2\leq b\leq r)\)的数

  \(n\leq 2\times {10}^{18},r\leq 62\)

题解

  我们考虑二分,求\(\leq m\)的不能被表示为\(a^b\)的数\(f(m)\)

  我们先忽略\(1\)

  我们钦定能被表示为\(a^2,a^3,a^5\)\(b\)为质数的数,贡献为\(\lfloor\sqrt[2]{m}\rfloor-1,\lfloor\sqrt[3]{m}\rfloor-1\cdots\),这样也会包含当\(b\)为合数时的情况,例如\(a^4={(a^2)}^2\)

  但我们算多了,例如\(a^3=b^2=c^6\),所以我们要减掉\(b\)为两个不同的质数的积的情况,即\(\lfloor\sqrt[6]{m}\rfloor-1,\lfloor\sqrt[10]{m}-1\rfloor\cdots\)

  然后加上\(b\)为三个不同的质数的积的情况,减掉\(b\)为四个不同的质数的积的情况……

  我们发现\(b=x\)时容斥系数为\(\mu(x)\)

  当\(b>62\)\(\lfloor\sqrt[b]{m}\rfloor=1\),所以不用继续往下算了

  还有,开\(n\)次根号可以用pow,不过要传long double参数进去,不然就会炸精度。

  但是这样子还会tle,因为有\(30000\)组数据

  我们发现\(f(x)\approx\sqrt{x}\)

  我们计算出\(f(n)\),然后每次把\(n\)加上\(n-f(n)\),可以很快得到答案

  时间复杂度:\(O(???)\)

  反正能过且常数巨大就对了

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<utility>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef long double ld;
int p[100];
int u[100];
int b[100];
int mx[100];
int cnt;
ll n;
int k;
ll fp(ll a,ll b)
{
	ll s=1;
	while(b)
	{
		if(b&1)
			s=s*a;
		a=a*a;
		b>>=1;
	}
	return s;
}
ll calc(ll n,ll x)
{
	ll s=floor(ld(pow(ld(n),ld(1)/x)));
	return s;
}
ll count(ll x)
{
	int i;
	ll s=0;
	ll nw;
	for(i=1;i<=62;i++)
		if(mx[i]<=k&&u[i])
		{
			nw=calc(x,i)-1;
			if(!nw)
				break;
			s+=u[i]*nw;
		}
	return s;
}
void solve()
{
	scanf("%lld%d",&n,&k);
	ll t=n;
	ll s=count(t);
	while(1)
	{
		t+=n-s;
		s=count(t);
		if(s==n)
			break;
	}
	printf("%lld\n",t);
}
int main()
{
	int i,j;
	cnt=0;
	memset(b,0,sizeof b);
	u[1]=1;
	mx[1]=1;
	for(i=2;i<=62;i++)
	{
		if(!b[i])
		{
			p[++cnt]=i;
			mx[i]=i;
			u[i]=-1;
		}
		for(j=1;j<=cnt&&i*p[j]<=62;j++)
		{
			b[i*p[j]]=1;
			mx[i*p[j]]=mx[i];
			if(i%p[j]==0)
			{
				u[i*p[j]]=0;
				break;
			}
			u[i*p[j]]=-u[i];
		}
	}
	int t;
	scanf("%d",&t);
	while(t--)
		solve();
	return 0;
}
posted @ 2018-03-05 20:16  ywwyww  阅读(171)  评论(0编辑  收藏  举报