zoukankan      html  css  js  c++  java
  • [AHOI 2018初中组] 根式化简 题解

    **[AHOI 2018初中组] 根式化简 题解 **

    好了告诉你们其实这就是一题非常简单的数论……

    先考虑最暴力的算法

    首先可以明了的一点就是如果我们把一个数 (N) 表示成 (x=k*a^3) 的形式,那么 (k) 一定满足 (k ≤ sqrt[3]{N})

    所以我们可以暴力枚举 (1- sqrt[3]{N}) 的每一个数 (x),只要满足 (x | N) ,我们就判断 (N/x)是否为立方数,这些立方数可以在 (sqrt[3]{N})的时间内预处理出来。

    我们看看数据范围,好的你已经 (get) (1-4) 个测试点,也就是 (40) 分了。

    有没有优化?

    我们注意到 (5,6) 两个特殊数据点:(x) 为立方数,这启示我们可以二分处理掉这一部分数据。

    很明显若 (i) 是递增的,那么 (i^3) 也是递增的,所以答案具有单调性。

    并且 (sqrt[4]{N} ≤ sqrt[3]{N} ≤ sqrt{N}) ,所以二分下界 $ sqrt{N}$,上界不好取,取 (sqrt[3]{10^{18}}=10^6) 即可。

    按照数据打程序,你已经可以通过 (1-6) 个测试点了。(60) 分在没想到正解的时候还是很可观的。

    总结启示,得到正解

    你知道 (N=k*a^3) ,那么应该会有:(k,a≤sqrt[3]{N}) 对吧?那么我们肯定不能暴力对 (N) 质因数分解,所以我们想想这些因数在什么范围内才是我们所要的?最简单的上界也是很容易想到的:(sqrt[3]{N})。看一眼数据,唔!又过了两个点(QAQ)

    单着并不是我们要的,我们在期望正解。很显然 (sqrt[3]{N}) 这个上界还是太大,因此我们需要观察还有没有更小的上界。其实我们发现可以把上界缩小到 (sqrt[4]{N}),然后$ forall i∈[1,sqrt[4]{N}], ext{且}i∈prime,imid N $,把 (N)(i) 全部除去,并且只要除的次数每逢 (3) 的倍数就把 (ans) 累乘上 (i)

    为什么这样可行?这么做极有可能剩下一个较大的 (k) 还可以继续分解啊?

    其实是不可能的,如果剩下除完了的 (N) 还能继续分解成上面那种形式的话,那么它早就被 ([2,sqrt[4]{N}]) 内的质因子除掉了,除非剩下了一个立方数。

    所以我们再次利用二分判断剩下的除完的那个 (N) 还是不是立方数就好了,如果是累乘上 (sqrt[3]{N})

    接下来根据代码来理解思路吧:

    #include<bits/stdc++.h>
    using namespace std;
    
    const int N = 4e4 + 10;
    const int M = 1e6 + 10;
    
    #define ll long long
    int prime[M]; bool v[M]; 
    
    int Prime(int n) {
    	int m = 0;
    	v[0] = v[1] = 1;
    	for(int i = 2; i <= n; i++) {
    		if(v[i] == 0) prime[++m] = i;
    		for(int j = 1; j <= m && prime[j] <= n / i; j++) {
    			v[i * prime[j]] = 1;
    			if(i % prime[j] == 0) break;	
    		}
    	}
    	return m;
    }
    
    ll p[M];
    int main() {
    	// 预处理立方根 
    	for(int i = 1; i <= M; i++) p[i] = (ll) i * i * i; 
    	// 预处理质数 
    	int m = Prime(N), T; ll x, ans = 1;
    	scanf("%d", &T);
    	while(T--) {
    		scanf("%lld", &x);
    		// 在 1-x^(1/4) 内枚举因子 
    		for(int i = 1, cnt = 0; i <= m && p[i] <= x; i++, cnt = 0) 
    			while(x % prime[i] == 0) {
    				cnt++, x /= prime[i];
    				if(cnt % 3 == 0) ans *= prime[i];
    			}
    		// 特判剩下的数 
    		ll k = lower_bound(p + 1, p + M + 1, x) - p;
    		if(k * k * k == x) ans *= k;
    		printf("%lld
    ", ans);
    		ans = 1;
    	}
    	return 0;
    }
    
  • 相关阅读:
    How to change hostname on SLE
    How to install starDIct on suse OS?
    python logging usage
    How to reset password for unknow root
    How to use wget ?
    How to only capute sub-matched character by grep
    How to inspect who is caller of func and who is the class of instance
    How to use groovy script on jenkins
    Vim ide for shell development
    linux高性能服务器编程 (二) --IP协议详解
  • 原文地址:https://www.cnblogs.com/Ning-H/p/11581108.html
Copyright © 2011-2022 走看看