题意:

L(x)为小于等于sqrt(x)的最大素数,R(x)为大于等于sqrt(x)的最小素数。

若一个数x只能被L(x)和R(x)其中一个整除,我们称之为奇异数。

对于一个正整数n,求[4,n]中所有奇异数的总和。

思路:

首先sqrt(x)为素数的话肯定不符合条件。

而且一个非素数的L(x)和R(x)肯定是相邻的素数,所以就考虑每一个素数到下一个素数这个区间。

那么在这个区间就要求出只能被L整除或者只能被R整除的数的和,如何求呢?

可以用容斥原理,可以先求出区间内能被L整除的数的和,能被R整除的数的和,再减去2倍的能同时被L和R整除的数就可以啦。

我先是因为筛法的时候少筛了比sqrt(1e12)大的素数WA了一发,然后又因为筛法的时候数组开得不对又WA了好几发,要考虑周到啊。

代码:
#define MAXN 1000000
typedef long long ll;
ll pri[MAXN+100];
ll pp[MAXN+100];
int num;
bool vis[MAXN+100];
void init()
{
    num=0;
    ll i,j;
    for(i=2;i<=MAXN+10;i++)
    {
        if(vis[i]==false)pri[num++]=i;
        for(j=0;j<num&&i*pri[j]<=MAXN+10;j++)
            vis[i*pri[j]]=true;
    }
    for(int i=0;i<num;i++)
        pp[i]=pri[i]*pri[i];
    //printf("%d\n",num);
}
int main()
{
    init();
    int t;
    scanf("%d",&t);
    ll n,ans;
    while(t--)
    {
        scanf("%lld",&n);
        ans=0;
        int pos=lower_bound(pp,pp+num,n)-pp;
        //printf("%d\n",pos);
        for(int i=0;i<pos;i++)
        {
            ll l=pri[i]*pri[i];
            ll r=min(n,pri[i+1]*pri[i+1]);
            ll m=pri[i]*pri[i+1];
            ll ldl=l/pri[i],ldr=r/pri[i];
            ll rdl=l/pri[i+1],rdr=r/pri[i+1];
            if(l>=rdl*pri[i+1])rdl++;
            ll mdl=l/m,mdr=r/m;
            if(l>=mdl*m)mdl++;
            //printf("(%lld,%lld)(%lld,%lld)(%lld,%lld)\n",ldl,ldr,rdl,rdr,mdl,mdr);
            ans+=(pri[i])*(ldl+ldr)*(ldr-ldl+1)/2;
            ans+=(pri[i+1])*(rdl+rdr)*(rdr-rdl+1)/2;
            ans-=2*m*(mdl+mdr)*(mdr-mdl+1)/2;
            ans-=l;
            if(r==pri[i+1]*pri[i+1])ans-=r;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!

计蒜客题 打表找规律 Previous
ST表 Next