1. 程式人生 > >2440: [中山市選2011]完全平方數

2440: [中山市選2011]完全平方數

bre 二分枚舉 告訴 esp can pre amp font rim

怎麽感覺一直在做市選的說。。搞得在中山的我都沒信心了。。。

好吧做這題主要是沖著莫比烏斯反演去的,然後實際上也是容斥原理的應用,跟反演沒什麽關系,但是莫比烏斯函數的一個應用。

首先將題目詢問第k個無平方因子數,那麽我立刻想到的是,這些數在莫比烏斯函數中的值是0(但是這個沒什麽用)

實際上的做法是二分枚舉範圍(我覺得這個是神來之筆),然後求這個範圍中有多少個無平方因子數。

那麽個數怎麽求,就是一個容斥原理的應用了:無平方因子數個數=包含0個質數平方的數個數(可能這一項有點難理解,但實際上就是總數)-包含1個質數平方的數個數+包含2個質數質數平方的數個數-包含3個質數平方的數個數……

(PS:具體這個數怎麽求呢,實際上是所以包含x個質數平方因子的數,用總數除以平方就可以得出這個平方出現了多少次了,舉個例子,範圍為40,那包含1個質數平方的數個數是多少呢,就是40/4+40/9+……)

那麽再來回顧一下莫比烏斯函數的定義,含有偶數個不同質數的數 函數值為1,含有奇數個不同質數的數 函數值為-1

發現了什麽?莫比烏斯函數值正好和上面容斥式子的正負是一樣的!舉個例子,4現在我可以輕松的告訴你,ta在容斥式子裏面是減去的,因為ta包含一個質數的乘積,但是我也可以說,因為2的莫比烏斯函數是-1。

那麽具體做法就是枚舉全部的平方數,根據莫比烏斯函數取決他是加還是減。1*1也是平方數啊,n/1*1*u(1)不就是總數咯~

#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long LL;
int pr,prime[210000],u[210000];
bool v[210000];
void mobius_inversion()
{
    pr=0;u[1]=1;
    memset(v,false,sizeof(v));
    for(int i=2;i<=210000;i++)
    {
        if(v[i]==false)
        {
            u[i]
=-1; prime[++pr]=i; } for(int j=1;j<=pr&&i*prime[j]<=210000;j++) { v[i*prime[j]]=true; if(i%prime[j]==0){u[i*prime[j]]=0;break;} u[i*prime[j]]=-u[i]; } } } LL check(LL x) { LL sum=0,t=sqrt(x); for(int i=1;i<=t;i++)sum+=u[i]*x/(i*i); return sum; } int main() { mobius_inversion(); int T; scanf("%d",&T); while(T--) { LL k; scanf("%lld",&k); LL l=k,r=2100000000LL,ans; while(l<=r) { LL mid=(l+r)/2; if(check(mid)>=k) { ans=mid; r=mid-1; } else l=mid+1; } printf("%lld\n",ans); } return 0; }

2440: [中山市選2011]完全平方數