本来一个Div2的C怎么会去写题解…但是这场真的很毒,然后我的解法估计和标算不一样,所以就写了下(Editorial还没出qaq)
题目大意:
给出q次询问,每次询问有多少个数满足l <= x <= r 且 x = ap 其中a > 0 , p > 1
似乎解法是预处理指数是3---64并且乱搞指数是2的
我的非标算做法:
考虑计算1 <= x <= p的个数,很显然答案就是前缀减一下
那么我们可以计算底数并计算贡献
显然对于所有的sqrt(p) < x <= p没有贡献,p^1/3 < x <= sqrt{p}的贡献是1……依次类推
那么对于一个x,暴力向下枚举开k次方就好了,注意精度,我的写法是在小范围内(k次根号小于10)暴力。
然后你就会发现你是GG的,因为你多算了答案
那么哪些数字对答案的贡献是重复的呢?不难发现是所有满足x = ap 其中a > 0 , p > 1的数字。那么我们就可以暴力递归下去
具体来说
1 long long find(long long l,long long r) 2 { 3 return (r - l + 1) - (cal(r) - cal(l - 1)); 4 }
(cal函数是计算前缀的玩意)
然后在cal函数里面递归调用find就好了。
于是你还是GG的,因为你会TLE。跑大数据似乎要7s
我们发现对于x小的时候会计算很多次,因此我们可以先暴力计算x <= 100000的答案,并在cal里面直接调用。
以下是细节部分:
cmath自带的那个pow函数极其zz…我写的是手写二分,很荣幸没有TLE。如果用库函数很容易wa
不知道为什么当x = 1e18的时候程序跑出来是错的,特判掉就好了(如果有dalao发现错误通知我一声啊)
如果你用这种数据999999999999999999 999999999999999999能把程序卡的很慢,不过cf的评测鸡还是很给力的
写二分的时候注意不要爆LL,我是直接用了一个数组存边界,详见代码
最后附上代码:
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<cstdlib> 5 using namespace std; 6 long long cal(long long); 7 long long find(long long l,long long r) 8 { 9 return (r - l + 1) - (cal(r) - cal(l - 1)); 10 } 11 int u[10] = {2,3,5,6,7,10,11,12}; 12 int ges[20] = {0,0,1e9,1e6,31623,3982,1000,373,178,100,64,44,32,25,20,16,14,12,10}; 13 int pes[15] = {0,0,60,38,30,26,24,22,20,19,18,18,17}; 14 int p[100005]; 15 inline long long poww(long long a,int b) 16 { 17 long long ans = 1; 18 while(b){ 19 if(b&1) ans = ans * a; 20 a = a * a; 21 b>>=1; 22 } 23 return ans; 24 } 25 inline long long qpow(long long x,int y) 26 { 27 long long l = 2 , r = ges[y]; 28 while(l < r){ 29 long long mid = (l+r) >> 1; 30 if(poww(mid , y) <= x) l = mid + 1; 31 else r = mid; 32 } 33 return l - 1; 34 } 35 inline int count(long long x,int y) 36 { 37 int l = 1 , r = pes[y]; 38 while(l < r){ 39 int mid = ((l+r)>>1) + 1; 40 if(poww((long long)y , mid) <= x) l = mid; 41 else r = mid - 1; 42 } 43 return l; 44 } 45 long long cal(long long x) 46 { 47 if(x == 1000000000000000000) return 1001003332; 48 if(x <= 100000) return p[x]; 49 long long t = qpow(x , 2); 50 long long ans = 0; 51 for(int i = 2;i <= 18 && t > 10;i++){ 52 long long q = qpow(x , (i+1)); 53 long long w = find(q+1 , t); 54 ans = ans + w * (i-1); 55 t = q; 56 } 57 for(int i = 0;u[i] <= t;i++){ 58 int j = count(x,u[i]) - 1; 59 if(j < 0) j = 0; 60 ans += j; 61 } 62 return ans + 1; 63 } 64 void Pre() 65 { 66 p[0] = 0; 67 p[1] = 1; 68 for(long long i = 2;i <= 100000;i++){ 69 for(long long j = i*i;j <= 100000;j *= i) p[j] = 1; 70 } 71 for(int i = 2;i <= 100000;i++){ 72 p[i] = p[i] + p[i-1]; 73 } 74 return; 75 } 76 int main() 77 { 78 int q; 79 scanf("%d",&q); 80 Pre(); 81 while(q--){ 82 long long l,r; 83 scanf("%I64d%I64d",&l,&r); 84 printf("%I64d\n",cal(r) - cal(l - 1)); 85 } 86 return 0; 87 }