B光滑数——NOIP模拟赛

B光滑数

Question

问题描述

  B为一个正整数,如果一个自然数N的因子分解式中没有大于B的因子,我们就称N是一个B光滑数。请你编一个程序,求出某个区间中所有的B光滑数的个数。

输入格式

  输入仅有一行,包含三个用空格隔开的整数n,m,b,其中1<=n<=2000000000,1<=m<=100000000,1<=b<=1000000。

输出格式

  输出仅一行。一个整数,表示区间[n,n+m]之间的B光滑数的个数。

样例输入

30 10 5

样例输出

4

Analysis

B光滑数其实是一个密码学的定义。

这题递推式非常显然。

首先,“大于B的因子”,显然就是质因子分解。那么我们可以找出小于b的所有质数。

然后状态显然是:

这个式子的意思是,在[x,y]内找因子小于第p个素数的数的个数。

然后递推式显然是:

显然是加法原理,这个状态的ans是由这两个状态组合出来的,其中这两个状态没有交集,不会重复。并且不会遗漏。

边界直接就可以出来了。不妨多写一些。

如果x>y,显然return 0;

如果y<=P[p],就是说区间内最大的数也比第p个素数小,显然每个数都成立,直接return y-x+1.这个边界似乎并不是一定要的,只不过为了减少计算而已。

如果p=1,

就是p的边界了,这时候质数是2,直接用log计算是2的次方的个数即可。

Ok,就是这么简单了。

Code A

#include<bits/stdc++.h>



using namespace std;



int P[2000001];

int maxx;



int prim(int b){

   P[1]=2;

   int p=1;

   int mm=0;

   bool flag;

   for (int i=3;i<=b;i+=2){

      flag=true;

      mm=sqrt(p)+1;

      for (int j=1;j<=mm and P[j];++j)

        if (!(i%P[j])){

           flag=false;

           break;

        }

      if (flag)

        ++p,

        P[p]=i;

   }

   maxx=p;

   return p;

}



int dfs(int p,int x,int y){

   if (x>y)

      return 0;

   if (y<=P[p])

      return y-x+1;

   if (x==y){

      for (int i=p;i<=maxx;++i)

        if (!(x%P[i]))

           return 0;

      return 1;

   }

        if (p==1)

                return trunc((log(y)/log(2))-trunc(log(x)/log(2)));

   int ans=0;

   ans=dfs(p-1,x,y)+dfs(p,(x-1)/P[p]+1,y/P[p]);

   return ans;

}



int main(){

   freopen("test.in","r",stdin);

   freopen("test.out","w",stdout);

   int n,m,b;

   cin>>n>>m>>b;

   int p;

   p=prim(b);

   int ans=0;

   ans=dfs(p,n,n+m);

   cout<<ans<<endl;

   return 0;

}

嗯很好,25分,发生了什么?

很简单,log的范围判断问题,这个直接算是不对的,因为无法判断两个数之间有几个整数。

于是改一改,改成直接暴力计算个数吧.

Code B 80

#include<bits/stdc++.h>



using namespace std;



int P[1000001];

int maxx;



int prim(int b){

   P[1]=2;

   int p=1;

   int mm=0;

   bool flag;

   for (int i=3;i<=b;i+=2){

      flag=true;

      mm=sqrt(p)+1;

      for (int j=1;j<=mm and P[j];++j)

        if (!(i%P[j])){

           flag=false;

           break;

        }

      if (flag)

        ++p,

        P[p]=i;

   }

   maxx=p;

   return p;

}



int dfs(int p,int x,int y){

   if (x>y)

      return 0;

   if (y<=P[p])

      return y-x+1;

   int ans=0;

        if (p==1){//NB

      long long  temp=1;

      for (;;){

        if (temp>=x and temp<=y)

           ++ans;

        if (temp>y)

           break;

        temp*=2;

      }

      return ans;

   }

        if (x==y){

                for (int i=p+1;i<=maxx;++i)

                        if (!(x%P[i]))

                                return 0;

                return 1;

        }

   ans=dfs(p-1,x,y)+dfs(p,ceil((x-1)/P[p])+1,ceil(y/P[p]));

   return ans;

}



int main(){

   freopen("test.in","r",stdin);

   freopen("test.out","w",stdout);

   int n,m,b;

   cin>>n>>m>>b;

   if (b==1){

      if (n>1){

        cout<<0<<endl;

        return 0;

      }

      else{

        cout<<1<<endl;

        return 0;

      }

   }

   int p;

   p=prim(b);

   int ans=0;

   ans=dfs(p,n,n+m);

   cout<<ans<<endl;

   return 0;

}

80,又发生了什么?

这就百思不得其解了。

先打个枚举的吧。

Code C 90

#include<bits/stdc++.h>



using namespace std;



int P[1000001];

int maxx;



int prim(int b){

   P[1]=2;

   int p=1;

   int mm=0;

   bool flag;

   for (int i=3;i<=b;i+=2){

      flag=true;

      mm=sqrt(p)+1;

      for (int j=1;j<=mm and P[j];++j)

        if (!(i%P[j])){

           flag=false;

           break;

        }

      if (flag)

        ++p,

        P[p]=i;

   }

   maxx=p;

   return p;

}



bool check(int k){

   int p=1;

   while (p<=maxx){

      while (!(k%P[p]))

        k/=P[p];

      ++p;

      if (k==1)

        return true;

   }

   if (k==1)

      return true;

   return false;

} 



int main(){

   freopen("test.in","r",stdin);

   freopen("test.out","w",stdout);

   int n,m,b;

   cin>>n>>m>>b;

   int up=n+m;

   int p=prim(b);

   int ans=0;

   if (b==1 and n==1){

      cout<<1<<endl;

      return 0;

   }

   if (b==1){

      cout<<0<<endl;

      return 0;

   }

   for (int i=n;i<=up;++i){

      if (check(i))

        ++ans;

   }

   cout<<ans<<endl;

   return 0;

}

有毒,能拿到90分。而且和之前的80分程序对拍上万次都找不到错误。

那么怎么递推递归呢?

按照题目意思,可以找出每个数的最大质因子。

然后怎么快速找出最大质因子呢?

老师说,应该用线性筛法,可以直接求出来。

然后当b小的时候,可以直接for循环找ans,这样比递归快。

Code C AC

#include<bits/stdc++.h>



using namespace std;



int vh[2000001],P[2000001];

long long n,m,b,maxx,cnt,js=-1;



void prime(){//线性筛法模板+求最大质因子

   for (long long i=0;i<=1000000;++i)

      vh[i]=i;

   for (long long i=2;i<=1000000;++i){

      if (vh[i]==i){

        P[cnt++]=i;

        if (i<=b)

           js=cnt-1;

      }

   for(long long  j=0;j<cnt  and   (longlong)i*P[j]<=1000000;++j){

        vh[i*P[j]]=max(vh[i],P[j]);//记录最大质因子

        if (!(i%P[j]))

           break;

      }

   }

}



long long cal(long long fir,long long sec){

   long long p=1,ans=0;

   while (p<=sec){

      if (p>=fir)

        ++ans;//为了避免神奇的小数的特判,只能这么打

      p*=(long long)2;

   }

   return ans;

}



long long dfs(long long p,long long x,long long y){

   if (x>y)

      return 0;

   if (p==0)

      return cal(x,y);

   long long ans=0;

   if (y<=100000){

      for (long long i=x;i<=y;++i)

        if (vh[i]<=P[p])

           ++ans;

      return ans;

   }

   ans=dfs(p-1,x,y)+dfs(p,(x-1)/P[p]+1,y/P[p]);

   return ans;

}



int main(){

   freopen("test.in","r",stdin);

   freopen("test.out","w",stdout);

   cin>>n>>m>>b;

   if (b==1){

      if (n>1){

        cout<<0<<endl;

        return 0;

      }

      else{

        cout<<1<<endl;

        return 0;

      }

   }

   prime();

   long long ans=0;

   ans=dfs(js,n,n+m);

   cout<<ans<<endl;

   return 0;

}

Conclusion

这题恶心,递推式很快就出来了,但是这个边界啊实在是。。。

小数问题要注意,用小数的地方注意特判,不特判的话就枚举吧。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值