【XSY1580】Y队列 容斥

来源:互联网 发布:淘宝刷流量平台 编辑:程序博客网 时间:2024/06/06 07:40

题目大意

  给你n,r,求第n个不能被表示为ab(2br)的数

  n2×1018,r62

题解

  我们考虑二分,求m的不能被表示为ab的数f(m)

  我们先忽略1

  我们钦定能被表示为a2,a3,a5b为质数的数,贡献为m21,m31,这样也会包含当b为合数时的情况,例如a4=(a2)2

  但我们算多了,例如a3=b2=c6,所以我们要减掉b为两个不同的质数的积的情况,即m61,m101

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

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

  当b>62mb=1,所以不用继续往下算了

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

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

  我们发现f(x)x

  我们计算出f(n),然后每次把n加上nf(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;}
原创粉丝点击