本文主要是介绍蓝桥云课 数的拆分(数论),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
题目链接
觉得这个题挺好的,留个档,至于题解在题目上已经有讲的很好的了。
思路:
数学思维题。
对一个数 x x x,根据唯一分解定理可以拆成 x = p 1 k 1 ∗ p 2 k 2 ∗ p 3 k 3 ∗ ⋯ ∗ p s k s x=p_1^{k_1}*p_2^{k_2}*p_3^{k_3}*\dots *p_s^{k_s} x=p1k1∗p2k2∗p3k3∗⋯∗psks的形式,然后我们要把这个形式转化为题目上 x = q 1 y 1 ∗ q 2 y 2 x=q_1^{y_1}*q_2^{y_2} x=q1y1∗q2y2 的形式。
其实比较容易发现内部的 q 1 , q 2 q_1,q_2 q1,q2 还是可以再拆的,因此 y 1 , y 2 y_1,y_2 y1,y2 我们选择尽可能小的数会比较好凑。比如说 q 6 q^6 q6 和 ( q 3 ) 2 (q^3)^2 (q3)2 是完全相同的,但是后者的 y = 2 y=2 y=2 就比较好凑,指数为 2 2 2 的倍数的情况显然更加常见。因此我们选择让 y 1 = 2 , y 2 = 3 y_1=2,y_2=3 y1=2,y2=3。
这样,对一个质因数 p i k i p_i^{k_i} piki,我们需要 q 1 y 1 ∗ q 2 y 2 = q 1 2 ∗ q 2 3 q_1^{y_1}*q_2^{y_2}=q_1^{2}*q_2^{3} q1y1∗q2y2=q12∗q23 包含它,假设 q 1 q_1 q1 有 x x x 个 p i p_i pi, q 2 q_2 q2 有 y y y 个 p i p_i pi,那么就有 k i = 2 ∗ x + 3 ∗ y k_i=2*x+3*y ki=2∗x+3∗y。而这个式子在 k i > 1 k_i>1 ki>1 时是总是有解的(非负整数解)。换句话说,只要 k i > 1 k_i>1 ki>1, p i k i p_i^{k_i} piki 就有办法分到 q 1 q_1 q1 和 q 2 q_2 q2 中去,否则就没可能。因此我们只要保证所有质因数都满足它的指数大于 1 1 1,那么就存在一种分配方案,把 x x x 可以转化为 q 1 y 1 ∗ q 2 y 2 q_1^{y_1}*q_2^{y_2} q1y1∗q2y2 的形式。
不过要分解质因数,我们需要筛到 1 0 18 = 1 0 9 \sqrt{10^{18}}=10^9 1018=109 以内的质因数,预处理就会超时。而且每个数我们都要分解一下,分解的时候需要枚举质因数,质因数的个数就不能太多。
考虑到当 x x x 转化为 q 1 y 1 ∗ q 2 y 2 = q 1 2 ∗ q 2 3 q_1^{y_1}*q_2^{y_2}=q_1^{2}*q_2^{3} q1y1∗q2y2=q12∗q23 的形式时,当 q 1 = 1 q_1=1 q1=1 或 q 2 = 1 q_2=1 q2=1 时,这个数就是个纯粹的平方数或者立方数,直接特判就行了。
当 q 1 , q 2 ≠ 1 q_1,q_2\not=1 q1,q2=1 时,这个数 x x x 就至少拥有了 5 5 5 个质因数。此时除了最大的质因数,其他较小的质因数一定都满足 ≤ 1 0 18 5 ≈ 3981 \le\sqrt[5]{10^{18}}\approx 3981 ≤51018≈3981,剩下的那个较大的质因数 q q q 只有可能是 q 1 , q 2 , q 3 , q 4 q^1,q^2,q^3,q^4 q1,q2,q3,q4(再多 它的大小就小于 1 0 18 5 \sqrt[5]{10^{18}} 51018 了),除开指数是 1 1 1 的情况,其他情况就是个平方数或者立方数,可以直接特判。
code:
#include <iostream>
#include <cstdio>
#include <map>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;ll prime[maxn],cnt;
bool vis[maxn];
void Eular(int n){vis[1]=true;for(int i=2;i<=n;i++){if(!vis[i])prime[++cnt]=i;for(int j=1,p=prime[1];j<=cnt && i*p<=n;p=prime[++j]){vis[i*p]=true;if(i%p==0)break;}}
}ll T,a;bool is2(ll x){ll l=1,r=x,mid;while(l<r){mid=l+r>>1;if(mid<=1e9 && mid*mid<x)l=mid+1;else r=mid;}return l*l==x;
}
bool is3(ll x){ll l=1,r=x,mid;while(l<r){mid=l+r>>1;if(mid<=1e6 && mid*mid*mid<x)l=mid+1;else r=mid;}return l*l*l==x;
}bool solve(ll a){if(is2(a) || is3(a)){return true;}for(int i=1,p=prime[1],c;i<=cnt && p<=a;p=prime[++i]){if(a%p==0){c=0;while(a%p==0){a/=p;c++;}if(c==1){return false;}}}if(is2(a) || is3(a))return true;else return false;
}int main(){Eular(5000);cin>>T;while(T--){cin>>a;puts((solve(a))?"yes":"no");}return 0;
}
这篇关于蓝桥云课 数的拆分(数论)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!