题意: 定义ax+1 为新的数,如果ax+1 不能分解成两个ay+1之积,那么称为素数!
求[1,n] 里的能分解成两个ax+1素数之积的数的个数。
很毒奶的题目!首先数据非常大!而且有坑点!
先说说性质吧!
(ax + 1) * (ay + 1) = a[ axy + x + y ] + 1 仍然为一个ax+1 数!
很明显我们可以仅对x、y分析,就变成连续区间[1,(n-1)/a] 内数分析!
如果数k 能表示成 k= axy + x + y,那么k(ak+1) 就不是素数!
线性筛法很快将其全部素数搞出!坑点来了!
数k = (ax + 1) (ay + 1) = (am + 1)(an + 1) ,且 (ax+1) 、(ay+1) 、(am+1)、(an+1)均为素数,那么就不能直接枚举两个素数之积不超过n的对数,有重复!
4641 = 51*91 = 21*221 ,如果你枚举计数,对不起gg了!
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <math.h>
#define llt long long
#include <map>
#define fi first
#define se second
#define lson (rt<<1)
#define rson ((rt<<1)+1)
using namespace std;
const int N =2*1e7+77;
int Prim[N];
bool is[N]={false};
bool boo[N]={false};
int main(){
// freopen("out1.txt","w",stdout);
int a,n;
scanf("%d%d",&a,&n);
int d = (n-1)/a;
int cnt = 0;
int ans = 0;
for(int i=1;i<=d;++i){
if(is[i]) continue;
Prim[cnt++] = i;
llt t = a*i+1;
for(llt j = 1ll*a*i*i+2*i;j<=d;j = j+t)
is[j] = true;
}
//直接枚举两个素数之积不超过n的对数,计算重复了!
// for(int i=0;i<cnt;++i)
// {
// int k = (d - Prim[i])/(a*Prim[i]+1);
// //cout<<k<<endl;
// ans = ans + (upper_bound(Prim+i,Prim+cnt,k)-Prim-i);
//
// }
// printf("%d\n",ans);
memset(boo,0,sizeof(boo));
for (int q=0;q<cnt;q++)
{
int i=Prim[q];
for (int k=0;k<cnt;k++)
{
llt j=Prim[k];
if ((a*i*j+i+j)>d) break;
boo[a*i*j+i+j]=1;
}
}
for (int i=1;i<=d;i++)
if (boo[i]) ans++;
cout<<ans<<endl;
}