前言:
这题难点在于复杂度分析.
实现:
首先很容易想到k假如不是质数答案为0.因为假如k不是质数,那么它一定可以写成比它小的数相乘.
其次假如答案可行,必定是大于等于k的质数的乘积的形式.因为假设不是比k的质数乘积,就是利用了到
的质数.这是不行的.
有了这两点,暴力的代码应该是都会写的..区间的
就等于
.然后令
是
以内能被
整除,不能被
到
整除的答案即可.至于cal怎么算,是利用容斥算的,
是区间的总答案,同时也是
乘的那个系数.前面讲到了,这个系数不能是
到
的数.然后递归下就好了.
#include <iostream> using namespace std; bool _prime(int x) { for(int i=2;i<=x/i;i++) { if(x%i==0) return false; }return true; }//O(sqrt(x)) int cal(int n,int k)//计算n以内,能被k整除但不能被2~k-1整除的数量. { if(!_prime(k)) return 0; if(k>=n) return (k==n); int res=n/k; for(int i=2;i<k&&i<=n/k;i++) { res-=cal(n/k,i); }return res; } int main() { int a,b,k; scanf("%d%d%d",&a,&b,&k); printf("%d\n",cal(b,k)-cal(a-1,k)); return 0; }
复杂度分析:
当k和n都很接近时,复杂度很低.(n/k)
当k很大时,复杂度也很低.(k>=n)
当k很小n很大时,复杂度也不高.(i<=k)
那么复杂度最高的时是:当k取sqrt(n)时,而n取1e9.
此时我们第一个for循环会运行sqrt(1e9)次,然后它的子程序的n就成了sqrt(1e9)了,而它子程序的k的复杂度最高的还是sqrt(n)时.如此分析时间复杂度应是接近根号的.