P9407 [POI2020-2021R3] Suma liczb pierwszych
World_Creater · · 题解
考虑
直接预处理出
当
考虑枚举质数个数,设现在枚举的质数个数为
时间复杂度
当然数字较大的时候一个一个判素数还是太笨蛋了,因为最终的暴力区间不会很大,因此可以考虑使用筛区间质数的方法,即:假如我们要筛
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,pre[5000005],prp[5000005],cnt;
bitset<100000005> f;
bitset<200005> chk;
void solve(int l,int r)
{
chk.reset();
// memset(chk,0,sizeof(chk));
for(int i=1;i<=cnt&&prp[i]*prp[i]<=r;i++)
{
// cerr<<"????"<<i<<"\n";
for(int j=(l+(prp[i]-1))/prp[i];j*prp[i]<=r;j++)
{
// cerr<<j*prp[i]<<"\n";
chk[prp[i]*j-l]=1;
}
}
}
int findnxt(int x,int g)
{
int i=x+1;
while(chk[i-g]) i++;
return i;
}
int findpre(int x,int g)
{
int i=x-1;
while(i>=2&&chk[i-g]) i--;
return i;
}
bool check(int n)
{
if(n==1) return 0;
for(int i=2;i*i<=n;i++)
{
if(n%i==0) return 0;
}
return 1;
}
signed main()
{
cin>>n;
for(int i=2;i<=20000000&&i<=n;i++)
{
if(!f[i]) prp[++cnt]=i;
for(int j=1;j<=cnt&&i*prp[j]<=20000000&&i<=n;j++)
{
f[i*prp[j]]=1;
if(i%prp[j]==0) break ;
}
}
for(int i=1;i<=cnt;i++)
{
pre[i]=pre[i-1]+prp[i];
}
int l=1;
if(n==1)
{
cout<<"NIE";
return 0;
}
if(check(n))
{
cout<<n<<" "<<n;
return 0;
}
for(int i=1;i<=cnt;i++)
{
while(l<i&&pre[i]-pre[l-1]>n) l++;
if(pre[i]-pre[l-1]==n)
{
cout<<prp[l]<<" "<<prp[i]<<"\n";
return 0;
}
}
for(int i=2;i<=5000;i++)
{
int t=n/i;
int base=20;
if(i<=5) base=200;
int LIM=max(t-max(i*base,100000ll),1ll);
solve(LIM,t+max(i*base,100000ll));
int r=findnxt(t,LIM);
vector<int> pp;
pp.emplace_back(r);
if(r<=2e7) break ;
int sum=r,cnt=1,l=r,it=0;
while(cnt<i) l=findpre(l,LIM),sum+=l,cnt++,pp.emplace_back(l);
// cerr<<"???"<<t<<" "<<l<<" "<<r<<"\n";
reverse(pp.begin(),pp.end());
while(sum<n) sum-=l,l=pp[++it],r=findnxt(r,LIM),sum+=r,pp.emplace_back(r);
if(sum==n)
{
cout<<l<<" "<<r;
cerr<<"\n"<<clock()*1.0/CLOCKS_PER_SEC;
return 0;
}
}
cout<<"NIE";
}