题意:给一个数字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;
}