题目链接:
OpenJudge C16D Extracurricular Sports
题意:
构造n个互不相同的数使得这n个数的最小公倍数等于它们之和。2<= n <= 200.如果不存在这样的构造输出-1.
分析:
可以证明2个数的时候不存在这样的构造。当n = 3 时,可以构造出1,2,3。当n = 4时,可以构造出1,4,5,10.
当n>4时,假设前n - 2个数的和是t(最小公倍数也是t),因为n = 3时的合法构造1,2,3,可以令第n - 1个数是2 × t,第n 个数是3×t,这时这n个数的最小公倍数和数字之和都是6*t,因此由n =3 和n =4 的情况,依次往下递推就可以得到答案了。
因为数字比较大,用数组存数字,简单的大数乘法。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <iostream>
#include <climits>
#include <iomanip>
#include <string>
using namespace std;
const int MAX_N = 210;
const int MAX_M = 1010;
int ans[MAX_N][MAX_M], sum[MAX_M], tmp[MAX_N], len;
void solve(int n)
{
memset(ans, 0, sizeof(ans));
int st ;
if(n & 1){
ans[1][0] = 1, ans[2][0] = 2;
ans[3][0] = 3;
len = 1, sum[0] = 6;
st = 5;
}else {
ans[1][0] = 1, ans[2][0] = 4;
ans[3][0] = 5, ans[4][0] = 10;
len = 2;
sum[0] = 0, sum[1] = 2;
st = 6;
}
for(int i = st; i <= n; i += 2){
int carry1 = 0, carry2 = 0, carry3 = 0;
int tmp1 = 0, tmp2 = 0, tmp3 = 0;
for(int j = 0; j < len; j++){
ans[i - 1][j] = sum[j] * 2 + carry1;
carry1 = ans[i - 1][j] / 10;
ans[i - 1][j] %= 10;
ans[i][j] = sum[j] * 3 + carry2;
carry2 = ans[i][j] / 10;
ans[i][j] %= 10;
tmp[j] = sum[j] * 6 + carry3;
carry3 = tmp[j] / 10;
tmp[j] %= 10;
}
if(carry1) ans[i - 1][len] = carry1;
if(carry2) ans[i][len] = carry2;
if(carry3){
tmp[len] = carry3;
len++;
}
for(int j = 0; j < len; j++){
sum[j] = tmp[j];
}
}
}
int main()
{
ios_base::sync_with_stdio(0);
cin.tie(0);
int T, n;
cin >> T;
while(T-- > 0){
cin >> n;
if(n == 2){
cout << -1 << endl;
continue;
}
solve(n);
for(int i = 1; i <= n; i++){
int ed = MAX_M - 10;
while(ans[i][ed] == 0) ed--;
for(int j = ed; j >= 0; j--){
cout << ans[i][j] ;
}
cout << endl;
}
//cout << "******" << len << "******" << endl;
}
return 0;
}