题意:
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 协议 ,转载请注明出处!