题目链接:点击打开链接
题意:
首先给定数组中有多少个数,只告诉你他们最小值为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
#include
#include
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++)
{
/*
最初是这样求最小公倍数的
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