最小公倍数 - 唯一分解定理
题意:给一个数字n,范围在[1,2^23-1],这个n是一系列数字的最小公倍数,这一系列数字的个数至少为2 个
例如12,是1和12的最小公倍数,是3和4的最小公倍数,是1,2,3,4,6,12的最小公倍数,是12和12的最小公倍数…
那么找出一个序列,使他们的和最小,上面的例子中,他们的和分别为13,7,28,24……显然最小和为7
思路分析 :可以确认的一点就是所要找的数之间两两互质
反证法 : 现有两个不是互质的数,他们的最小公倍数为 n , gcd 不为 1 ,此时计算可以得到一个和, 如果让这两个数同时除以 gcd , 那么我们再次计算和的时候会发现和是明显减少的
如果这点明确后,就可以根据唯一分解定理去计算答案了,因为其可以保证所有相乘的数之间两两互质
注意要特判一些情况
代码示例 :
#define ll long long const int maxn = 1e6+5; const int mod = 1e9+7; const double eps = 1e-9; const double pi = acos(-1.0); const int inf = 0x3f3f3f3f; ll n; vector<ll>ve; ll pt[maxn]; ll cnt[maxn]; void init(){ memset(pt, 1, sizeof(pt)); for(ll i = 2; i <= 1000000; i++){ if (pt[i]){ ve.push_back(i); for(ll j = i+i; j <= 1000000; j += i) pt[j] = 0; } } } int main() { //freopen("in.txt", "r", stdin); //freopen("out.txt", "w", stdout); init(); int kase = 1; while(~scanf("%lld", &n) && n){ memset(cnt, 0, sizeof(cnt)); if (n == 1) {printf("Case %d: 2\n", kase++); continue;} for(ll i = 0; i < ve.size(); i++){ while(n%ve[i] == 0){ n /= ve[i]; cnt[i]++; } if (n == 1) break; } ll ans = 0; int f = 0; if (n != 1) {ans = n; f++;} for(ll i = 0; i < ve.size(); i++){ if (cnt[i]) { ans += pow(ve[i], cnt[i]); f++; } } if (f == 1) ans++; printf("Case %d: %lld\n",kase++, ans); } return 0; }
东北日出西边雨 道是无情却有情