Live2d Test Env

CodeForces - 83D:Numbers (数学&递归 - min25筛 )

pro:给定三个整数L,R,P求[L,R]区间的整数有多少个是以P为最小因子的。L,R,P<2e9;

sol:

一: 比较快的做法是,用函数的思想递归。

    用solve(N,P)表示求1到N有多少数字多少个的最小因子是P;

     1,首先P是合数,或者N<P;solve=0;

     2,否则,如果P*P>=N;solve=1;

     3,solve=N/P-solve(N/P,i);     2<=i<P

 由于P主要分布在sqrt(N),而且N每次log级别减小,所以收缩得很快。具体的复杂度我证明不来,但是感觉过程和min25筛差不多。 (62ms

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=200010;
bool check(int P)
{
    for(int i=2;i*i<=P;i++)
      if(P%i==0) return false;
    return true;
}
int solve(int N,int P)
{
    if(!check(P)||N<P) return 0;
    if(N/P<P) return 1;
    int res=N/P;
    rep(i,2,P-1) res-=solve(N/P,i);
    return res;
}
int main()
{
    int A,B,P;
    scanf("%d%d%d",&A,&B,&P);
    printf("%d\n",solve(B,P)-solve(A-1,P));
    return 0;
}

 

 

二:当时还不流行min25筛,否则这题大部分人都可以套板子了。我们知道min25的过程其实就是每次可以得到最小素因子为p的数的个数(或者之和),所以改一下板子即可(128ms

#include<bits/stdc++.h>
using namespace std;
#define ll int
const int maxn=200010;
ll Sqr,vis[maxn],pri[maxn],tot,m,id1[maxn],id2[maxn];
ll g[maxn],w[maxn]; //sp前i个素数之和。
void Sieve(int n)
{
    tot=0; vis[1]=1;
    for(int i=2;i<=n;i++){
        if(!vis[i]) pri[++tot]=i;
        for(int j=1;pri[j]<=n/i;j++){
               vis[i*pri[j]]=1;
            if(i%pri[j]==0) break;
        }
    }
}
bool check(int P)
{
    for(int i=2;i*i<=P;i++)
      if(P%i==0) return false;
    return true;
}
ll solve(ll n,ll K)
{
    if(n<K) return 0;
    if(!check(K)) return 0;
    if(K>n/K) return 1;
    Sqr=sqrt(n); Sieve(Sqr); ll res=0; m=0;
    for(ll i=1,j;i<=n;i=j+1){
        j=n/(n/i); w[++m]=n/i;
        if(w[m]<=Sqr) id1[w[m]]=m;
        else id2[n/w[m]]=m;
        g[m]=w[m]-1; //1到n的素数个数,先设为n-1(1不考虑
    }
    for(int j=1;j<=tot;j++){
      for(int i=1;i<=m&&pri[j]<=w[i]/pri[j];i++){
        int k=(w[i]/pri[j]<=Sqr)?id1[w[i]/pri[j]]:id2[n/(w[i]/pri[j])];
        g[i]=g[i]-(g[k]-(j-1));
        if(pri[j]==K&&i==1) res+=g[k]-(j-1); //K去筛,[1,N]时
      }
    }
    return res+1;//加上素数自己
}
int main()
{
    int l,r,k;
    scanf("%d%d%d",&l,&r,&k);
    printf("%d\n",solve(r,k)-solve(l-1,k));
    return 0;
}

 

posted @ 2019-05-12 19:41  nimphy  阅读(503)  评论(0编辑  收藏  举报