aplusb 简单的水题

Description
SillyHook要给小朋友出题了,他想,对于初学者,第一题肯定是a+b啊,但当他出完数据后神奇地发现.in不见了,只留下了一些.out,他想还原.in,但情况实在太多了,于是他想要使得[a,b] ([a,b] 表示a,b 的最小公倍数)尽可能大。
Input
输入文件的第一行一个整数T表示数据组数。
接下来T行每行一个整数n,表示.out中的数值,即a+b=n。
Output
共T行,每行一个整数表示最大的[a,b]的值。
Sample Input
3
2
3
4
Sample Output
1
2
3
Data Constraint
30%的数据满足 T≤10,n≤1000
100%的数据满足T≤10000 ,n≤1e9

观察题目,可以知道,对于一组数据,题目告诉我们一个n,我们求取任意两个数a,b,在a+b=n的情况下,使得 lcm(a,b)最大。
毫无疑问,因为 lcm(a,b)×gcd(a,b) = a×b ,所以,我们有 lcm(a,b) = ab/(gcd(a,b))
由于a+b=n,如果我们设 p=n/2-a,则 b-n/2=n/2-a=p
所以,我们很容易可以得到 a=n/2-p , b=n/2+p,所以ab = (n^2)/4-p^2,所以,n固定的情况下,p越小,a,b的乘积越大。也就是说,a,b距离n/2越近,ab得到的值就越大。
再看gcd(a,b),我们就已经可以得到一部分的答案了。
当n为奇数时,可以将n拆成a=n/2,b=n/2+1,我们又知道a,b相差为1,所以它们的gcd(a,b)=1,所以我们可以得到答案 lcm(a,b)=(n/2)×(n/2+1)。
但是,n为偶数时,我们该怎么解决问题呢?
首先,我们还是优先考虑a,b距离最近的情况。也就是a=b=n/2,可是,这种情况下ab/gcd(a,b)=n/2,显然,还不如我让a=1,b=n-1呢。
不过,为了保证gcd(a,b)尽可能小,并且ab尽可能大,我们拆分还是尽量选择向平均值靠拢的方式。
我们会发现,n为偶数时,依旧可以分出两种情况,我们会发现若是 (n/2) 时偶数,则我们可以将n拆成 a=n/2-1,b=n/2+1,因为n/2是偶数,所以a,b是奇数,并且由于b-a=2,所以a,b的最大公约数gcd(a,b)=1。
证明:它们的最大公约数若是i,则a=xi,b=yi,并且b-a=2,所以b-a=(y-x)i=2,因为i若是等于2,则a,b不可能是奇数,所以i只能等于1。
因此,我们可以知道,n是4的倍数时,答案lcm(a,b)=(n/2-1)(n/2+1)=(n/2)^2-1
那么,(n/2)是奇数我们该如何研究呢。
我们可以分两类,一类是ab更大的(n/2-1)(n/2+1),但是此时gcd(a,b)=2。
一类是ab稍微小一些的(n/2-2)(n/2+2),而此时gcd(a,b)=1。
证明:若有a=n/2-2,b=n/2+2,已知其均为奇数,且a+4=b,设gcd(a,b)=i,a=xi,b=yi,则b-a=(y-x)i=4。因为i的因数中不可能存在偶数,否则a,b不能为奇数,所以i=1.
那么我们可以采取做差的方法,使得 (n/2-1)(n/2+1)/2-(n/2-2)(n/2+2),看得到的值为正还是为负。若是为正,则说明采取更接近平均值的 a=(n/2-1),b=(n/2+1)更合适,若为负,则说明采取并不那么接近平均值,但是公约数为1的 a=(n/2-2),b=(n/2+2) 更合适。
做差后,我们得到的式子为 (1/8)(28-n^2),因此,在n≤5的情况下,值为正,否则为负。
因为我们讨论的是n为偶数,(n/2)为奇数的情况,所以,n=2时,答案为1,否则答案为(n/2-2)(n/2+2)。
所以,我们就可以做对这道水题了。代码如下:

#include <bits/stdc++.h>

#define LL long long

using namespace std;

int t;
LL n; 

inline LL read()
{
    LL x=0;
    char c=getchar();
    while ((c<'0')||(c>'9'))
        c=getchar();
    while ((c>='0')&&(c<='9'))
        x=(x<<3)+(x<<1)+c-'0',c=getchar();
    return x;
}

int main()
{
    scanf("%d",&t);
    while (t--)
    {
        n=read();
        if (!n)
            printf("0\n");
        else
            if (n&1)
                printf("%lld\n",(n/2)*(n/2+1));
            else
                if (n&2)
                    if (n==2)
                        printf("1\n");
                    else
                        printf("%lld\n",(n/2-2)*(n/2+2));
                else
                    printf("%lld\n",(n/2-1)*(n/2+1));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/CutieDeng/article/details/81941127