min25筛
可以低于线性的解决1到N中的质数的k次幂的求和的问题,并且在处理了N之后对于1到N中数论分块所需的点x(l,r)都可以通过val=g[ID(x)]以O(1)的代价获取到
如果不需要多次查询,建议把命名空间外的定义放到min25命名空间里面
#define LL long long
#define ll long long
const int N = 1000000 + 10;
int prime[N], id1[N], id2[N], flag[N], ncnt, m;
LL g[N], sum[N], a[N], T;
LL n;
LL mod;
namespace min25{inline LL ps(LL n,LL k) {LL r=1;for(;k;k>>=1){if(k&1)r=r*n%mod;n=n*n%mod;}return
r;}void finit(){ // 最开始清0memset(g, 0, sizeof(g));memset(a, 0, sizeof(a));memset(sum, 0, sizeof(sum));memset(prime, 0, sizeof(prime));memset(id1, 0, sizeof(id1));memset(id2, 0, sizeof(id2));memset(flag, 0, sizeof(flag));ncnt = m = 0; }int ID(LL x) {return x <= T ? id1[x] : id2[n / x];}LL calc(LL x) {return x - 1;//质数次数和 //return x * (x + 1) / 2 - 1;//质数一次和 //return x * (x + 1) * (2 * x + 1) / 6 - 1;}void init(LL x) {T = sqrt(x + 0.5);for (int i = 2; i <= T; i++) {if (!flag[i]) prime[++ncnt] = i, sum[ncnt] = sum[ncnt - 1] + 1;//次数和 //if (!flag[i]) prime[++ncnt] = i, sum[ncnt] = sum[ncnt - 1] + i; //一次和 //if (!flag[i]) prime[++ncnt] = i, sum[ncnt] = sum[ncnt - 1] + (LL)prime[i] * prime[i]; // 修改3:记录质数平方和for (int j = 1; j <= ncnt && i * prime[j] <= T; j++) {flag[i * prime[j]] = 1;if (i % prime[j] == 0) break;}}for (LL l = 1; l <= x; l = x / (x / l) + 1) {a[++m] = x / l;if (a[m] <= T) id1[a[m]] = m; else id2[x / a[m]] = m;g[m] = calc(a[m]);}for (int i = 1; i <= ncnt; i++)for (int j = 1; j <= m && (LL) prime[i] * prime[i] <= a[j]; j++)g[j] = g[j] - (g[ID(a[j] / prime[i])] - sum[i - 1]);//次数和 //g[j] = g[j] - (LL) prime[i] * (g[ID(a[j] / prime[i])] - sum[i - 1]);//一次和 // g[j] = g[j] - (LL) prime[i] * prime[i] * (g[ID(a[j] / prime[i])] - sum[i - 1]);//平方和 }LL solve(LL x) {if (x <= 1) return 0ll;//修改的时候注意这里要微调一下 return n = x, init(n), g[ID(n)];}}using namespace min25;
ll count(ll n){ll l=1,r=1e9,sqn=1,tmp;ll mid=(l+r)/2;while(l<=r){mid=(l+r)/2;tmp=mid*mid;if(tmp<=n){sqn=mid;l=mid+1;}else r=mid-1;}finit();solve(sqn);ll ans=0,tl=0,tr=0;for(ll l=1,r;l<=sqn;l=r+1){r=sqn/(sqn/l);tl=g[ID(l-1)];tr=g[ID(r)];ans+=(tr-tl)*(sqn/l);}sqn++;ll now=sqn;for(ll pp=2;pp<=sqrt(sqn);pp++){if(now%pp==0){if(sqn*sqn-pp<=n) ans++;}while(now%pp==0) now/=pp;}if(now!=1) if(sqn*sqn-now<=n) ans++;return ans;
}int main(){ll l,r;std::cin>>l>>r;std::cout<<count(r)-count(l-1);
}