Wannafly Winter Camp 2019 Day1 C 拆拆拆数

探讨了将两个整数拆分成多个互质数的算法,通过巧妙构造满足题目要求,涉及数学技巧与特判处理。

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

https://zhixincode.com/contest/3/problem/C?problem_id=36
题意:将两个数 A 、 B A、B AB分别拆成 n n n个数 a 1 . . a n a_1..a_n a1..an b 1 . . b n b_1..b_n b1..bn ( a i , b i ! = 1 ) (a_i,b_i!=1) (ai,bi!=1),且每对 a i a_i ai b i b_i bi互质,若有多组符合条件,输出 n n n最小的任意一组。
∑ i = 1 n a i = A 、 ∑ i = 1 n b i = B \sum\limits_{i=1}^{n} a_i=A、\sum\limits_{i=1}^{n} b_i=B i=1nai=Ai=1nbi=B且对于任意 i &lt; = n i&lt;=n i<=n g c d ( a i , b i ) = 1 gcd(a_i,b_i)=1 gcd(ai,bi)=1

这题wls说卡构造,暴力找素数试就可以过,然而被我们用十分妖娆的方式构造给过了。。。
首先如果想到了两个数都是偶数的情况,假设两个数中的较小值为 A A A,较大值为 B B B,可以将 A A A拆成 2 2 2 A − 2 A-2 A2,把 B B B拆成 A − 1 A-1 A1 B − ( A − 1 ) B-(A-1) B(A1),因为 A A A B B B都是偶数,所以 B − ( A − 1 ) B-(A-1) B(A1)必定是个奇数,该奇数必定与 2 2 2互质,而相邻的两个数 A − 1 A-1 A1 A − 2 A-2 A2也必定是互质的。同理,对于两个奇数的情况这样构造也是可以的。但是在测试时发现,如果两个数相等, B − ( A − 1 ) = 1 B-(A-1)=1 B(A1)=1不符合题目要求,因此需要特判这种情况,随便用两个素数就可以构造出该情况的解。
然后考虑两个数一奇一偶的情况,假设两个数中的奇数为 A A A,偶数为 B B B,可以将A拆成 2 2 2 A − 2 A-2 A2,将 B B B拆成 B − 3 B-3 B3 3 3 3,这样 B − 3 B-3 B3是奇数,显然 2 2 2 B − 3 B-3 B3可以保证互质,但是 A − 2 A-2 A2 3 3 3可能不互质,所以需要判断 A − 2 A-2 A2是否是 3 3 3的倍数。如果是 3 3 3的倍数,则将 A A A拆成 4 4 4 A − 4 A-4 A4,否则拆成 2 2 2 A − 2 A-2 A2,这样因为如果 A − 2 A-2 A2 3 3 3的倍数, A − 4 A-4 A4必定不是 3 3 3的倍数。但是此时又有一个小问题就是当 A = 5 A=5 A=5时, A − 4 = 1 A-4=1 A4=1又不符合题目要求,因此有需要特判这种情况,可以将 5 5 5拆成 2 2 2 3 3 3,将 B B B拆成 5 5 5 B − 5 B-5 B5
就这样,在又臭又多的特判下,冗长丑陋的代码就可以过了这个题,而且覆盖所有可能情况。

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;

int T;
long long a,b;
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%lld%lld",&a,&b);
        if(__gcd(a,b)==1)
            printf("1\n%lld %lld\n",a,b);
        else
        {
            if(a==b)
            {
                printf("2\n");
                printf("%lld %lld\n",2LL,3LL);
                printf("%lld %lld\n",a-2LL,b-3LL);
            }
            else if((a%2==0&&b%2==0)||(a%2==1&&b%2==1))
            {
                if(a<b)
                {
                    printf("2\n");
                    printf("%lld %lld\n",2LL,b-(a-1LL));
                    printf("%lld %lld\n",a-2LL,a-1LL);
                }
                else
                {
                    printf("2\n");
                    printf("%lld %lld\n",a-(b-1LL),2LL);
                    printf("%lld %lld\n",b-1LL,b-2LL);

                }
            }
            else
            {
                if(a%2==1)
                {
                    if((a-2)%3==0)
                    {
                        if(a==5)
                        {
                            printf("2\n");
                            printf("%lld %lld\n",2LL,b-5LL);
                            printf("%lld %lld\n",3LL,5LL);
                        }
                        else
                        {
                            printf("2\n");
                            printf("%lld %lld\n",4LL,b-3LL);
                            printf("%lld %lld\n",a-4LL,3LL);
                        }
                    }
                    else
                    {
                        printf("2\n");
                        printf("%lld %lld\n",2LL,b-3LL);
                        printf("%lld %lld\n",a-2LL,3LL);
                    }
                }
                else
                {
                    if((b-2)%3==0)
                    {
                        if(b==5)
                        {
                            printf("2\n");
                            printf("%lld %lld\n",a-5LL,2LL);
                            printf("%lld %lld\n",5LL,3LL);
                        }
                        else
                        {
                            printf("2\n");
                            printf("%lld %lld\n",3LL,b-4LL);
                            printf("%lld %lld\n",a-3LL,4LL);
                        }
                    }
                    else
                    {
                        printf("2\n");
                        printf("%lld %lld\n",3LL,b-2LL);
                        printf("%lld %lld\n",a-3LL,2LL);
                    }
                }
            }
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值