OpenJudge C16D Extracurricular Sports(构造/大数)

题目链接:
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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值