hdu5223(GCD)

一道数论题目,要求根据给定区间的最大公约数复原原始序列。初始所有数为1,若某区间GCD为ans,则区间内所有数应为ans的倍数。错误在于数据类型使用不当,int乘法可能溢出,解决方法是使用long long进行计算并检查越界。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:点击打开链接

题意:

首先给定数组中有多少个数,只告诉你他们最小值为1,不告诉你每个数字是多少,要求根据给定区间中数的最大公约数,复原原来的序列。

思路:

先把所有的数初始化为1,然后根据指定问题,如果某一区间的最大公约数是ans, 那么这个区间中的所有数字都是ans的倍数,所以,把区间中的每个数字都赋值为原数字和ans的最小公倍数即可。


这道题本来是一道水题,但由于自己的粗心而导致在比赛中一直是wrong answer。错误的原因就是数据类型用错了。首先看到数据范围是10的9次方,在int范围内(int范围是2的32次方比 4 乘以10的9次方多一点),所以我就考虑使用int行来保存数组中的所有数字,但由于在求最小公倍数是涉及到两个数的乘法,所以有可能会超出int的范围,本来很好处理的问题,但我竟然又声明了一个long long int 的变量用来保存两个int型数据的乘积,这样做是愚蠢的,因为两个int型数据相乘时结果还是int型,用long long int 保存两个int型数据的乘积就是先把两个int型数据相乘的到的int型结果强制转化为long long int 而已, 在相乘中就会出现超出范围的问题,即相乘的结果就是错误的,所以在赋值后,还是错误的。  

解决的办法应该是先把两个int型分别赋值到两个long long int型变量中,然后把两个long long int 型变量相乘后除以他们的最大公约数,最后检查 这个数是否越界,如果不越界就可以赋值给对应的int型变量了。

代码如下:

#include <iostream>
#include <cstdio>
#include <algorithm>

using namespace std;
const int MAXN= 1005;
int a[MAXN], l[MAXN], r[MAXN], ans[MAXN], n, q;
int gcd(int a, int b)
{
    int tem;
    while(b != 0)
    {
        tem = a % b;
        a = b;
        b = tem;
    }
    return a;
}
int scd(long long int a,long long int b)   //注意要用long long int 或 long int
{
        return (long long)(a*b)/gcd(a,b);
}
int newgcd(int l, int r)  //区间在l,r范围的最大公约
{
    long long int i, tem = a[l];
    for(i = l+1; i <= r; i++)
    {
        tem = gcd(tem, a[i]);
    }
    return tem;
}
void init(int num)
{
    int i;
    for(i = 1; i <= num+2; i++)
    {
        a[i] = 1;
    }
}
int main()
{
    int i, j, t;
    bool ok;
    long long int tem;
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d%d", &n, &q);
        init(n);
        ok = true;
        for(i = 1; i <= q; i++)
        {
            scanf("%d%d%d", &l[i], &r[i], &ans[i]);
            if(ans[i] == 1)
                continue;
            for(j = l[i]; j <= r[i]; j++)
            {
<span style="white-space:pre">		</span>/*
                最初是这样求最小公倍数的
                tem = a[j] * ans[i];    //如果乘积超过整型的范围,赋值给tem的数还是错误的。
                a[j] = tem / gcd(a[j], ans[i]);
                */
                tem = scd(a[j], ans[i]);  //求最小公倍数
                if(tem > 1000000000)     //注意题中的条件,做题容易只考虑下界而不考虑上界。
                {
                    ok =false;
                    break;
                }
                else
                {
                    a[j] = tem;
                }
            }
        }
        if(ok != false)
        {
            for(i = 1; i <= q; i++)
            {
                if(newgcd(l[i], r[i]) != ans[i])
                {
                    ok = false;
                    break;
                }
            }
        }
        if(ok)
        {
            for(i = 1; i < n; i++)
            {
                printf("%d ", a[i]);
            }
            printf("%d\n", a[i]);
        }
        else
        {
            printf("Stupid BrotherK!\n");
        }
    }
    return 0;
}


109109


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值