CodeForces 833B 详细题解(貌似是四边形优化)

本文介绍了一种关于蛋糕包装的问题,通过不同的算法优化策略,包括O(n^3k)、O(n^2k)及O(nk)的时间复杂度优化过程,实现对蛋糕连续分割以达到最大总价值。

833B - The Bakery

B. The Bakery

time limit per test2.5 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output

Some time ago Slastyona the Sweetmaid decided to open her own bakery! She bought required ingredients and a wonder-oven which can bake several types of cakes, and opened the bakery.

Soon the expenses started to overcome the income, so Slastyona decided to study the sweets market. She learned it’s profitable to pack cakes in boxes, and that the more distinct cake types a box contains (let’s denote this number as the value of the box), the higher price it has.

She needs to change the production technology! The problem is that the oven chooses the cake types on its own and Slastyona can’t affect it. However, she knows the types and order of n cakes the oven is going to bake today. Slastyona has to pack exactly k boxes with cakes today, and she has to put in each box several (at least one) cakes the oven produced one right after another (in other words, she has to put in a box a continuous segment of cakes).

Slastyona wants to maximize the total value of all boxes with cakes. Help her determine this maximum possible total value.

Input

The first line contains two integers n and k (1 ≤ n ≤ 35000, 1 ≤ k ≤ min(n, 50)) – the number of cakes and the number of boxes, respectively.

The second line contains n integers a1, a2, …, an (1 ≤ ai ≤ n) – the types of cakes in the order the oven bakes them.

Output

Print the only integer – the maximum total value of all boxes with cakes.

题目 m个包裹, n个蛋糕,连续划分,每个包裹的价值为这个包裹内蛋糕的种类数,相同数字的蛋糕为同一种蛋糕。求最大总价值。

这里写图片描述
有助于理解的图,可以帮助刷表思路。

O(nnnk)

顺序:从左往右,从上往下

for k = 1 to m
    for i = k to n
        for j = k-1 to i-1
            dp[k][i] = max(dp[k][i], dp[k-1][j]+val(j+1, i) );

状态数:nk
状态转移复杂度:枚举k O(n), val(j+1, i)的计算O(n)。
总复杂度O(nnnk)

O(nnk)

顺序:从左往右,从上往下
均摊复杂度优化。
val值从(k , i)~( i , i ) 在第三层循环中都会用到,所以,可以在第三层之间先枚举出来,这样就是O(nk*2n)
逆序遍历,记录出现的种类,可以用set。

for k = 1 to m
    for i = k to n
        for j = i to k
            set.insert(a[j])
            val[j] = set.size
        for j = k-1 to i-1
            dp[k][i] = max(dp[k][i], dp[k-1][j]+val[j+1] );

O(nk)

类似于隔板法的思想。orz V8老师。
一段k个数字的数列,分割成n份,价值为n份价值总和。这样的问题,自然是在k个数字间插n-1个隔板。
直接用的定理,V8老师说可以反证法证明,但是很长。。。我也还没找。

1. 尽量平均会使价值更大
2. 相同n份,k越大,最后一个隔板越靠后,保持平均嘛。
3. 相同k个,n越大,最后一个隔板越靠后,保持平均嘛。

在这题中,n个蛋糕,分到k个包裹里,满足上面的形式,所以,可以记录转移位置,缩小最后枚举的范围。
范围,自然一左一右,也就是找转移位置的左边界和右边界。根据上面的定理,[k, i]的左边界不会小于[k,i-1]也不会小于[k-1,i], 右边界不会大于[k+1,i]也不会大于[k,i+1],依次在[k,i]的左、上、下、右,任意选两个。这里我选了左和下,如果想要左和下来推出当前位置,那么,就需要更改计算顺序,以提前求出左和下的值。
顺序:从下往上从左往右
因为以前计算val是O(n)的,n方是过不了的,在这里可以优化为O(1),这样复杂度就为O(nk),优化方法如下:
因为是从下往上从左往右,所以说,就是一列一列的刷表,每递增一列,比如从 i -> i+1,需要的val只是从(?,i )到了( ? , i+1),假设已知到第i列的val,在第i+1列中,当算到一个具体的区间时,我们只要看一下a[i+1](当前位置的值)在不在这个区间内,在的话,不变,不在的话,加一,如何快速知道在不在这个区间呢?可以预处理出于在当前位置的左边,与 当前位置的值 相同的元素的位置在哪。这样,只需要看与它相同的前一个值在不再这个区间内,在的话,就不变,不在的话,就加一,实现了O(1)更新val。

貌似这是平行四边形法则优化?不懂这法则,要有了解的前辈,请不吝赐教。orz。

表述的并不是很清楚,若哪里有疑问,请及时提出。orz V8老师。

可以用滚动数组优化空间,懒得优化了,反正不会爆。

贴代码:

O(nk)的解法

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int MAXN = 35005;
const int MAXK = 55;
int n, m; // n 蛋糕的数量 m 包裹的数量,即题目k
int a[MAXN];
int dp[MAXK][MAXN];
int tran[MAXK][MAXN];  // 转移位置
int last[MAXN];  // 与当前位置值相同的左边最近的点的位置
int val[MAXN];   
int updated[MAXN]; // 一列中val只能更新一次,该数组避免重复更新
void get_last() {
    int rec[MAXN];
    memset(rec, 0, sizeof(int)*n+5);
    for(int i = 1; i <= n; i++) {
        last[i] = rec[a[i]];
        rec[a[i]] = i;
    }
}
int main() {
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++)
        scanf("%d", &a[i]);
    get_last();

    for(int i = 1; i <= n; i++) {
        for(int k = min(i, m); k >= 1; k--) {
            int l = max(tran[k][i-1], k-1);  // 左边界
            int r = (tran[k+1][i] == 0 ? i-1 : tran[k+1][i]);  // 右边界

            // 边界包含其中
            for(int j = l; j <= r; j++) {
                if(updated[j+1] != i) {  // 更新val,关键!!!  
                    updated[j+1] = i;
                    val[j+1] += (last[i]<j+1);
                }

                if(dp[k][i] < dp[k-1][j]+val[j+1]) {
                    dp[k][i] = dp[k-1][j]+val[j+1];
                    tran[k][i] = j;  // 记录转移位置
                }
            }
        }
    }
    printf("%d", dp[m][n]);
    return 0;
}

O(nnk)的解法

void onnk() {  // 复杂度为O(nnk) 
    memset(dp, 0, sizeof(dp));
    for(int k = 1; k <= m; k++) {      // 枚举第k个包裹 
        for(int i = k; i <= n; i++) {  // 枚举第k个包裹的结束位置 
            // 逆序计算val值,均摊复杂度 
            set<int> mark;
            for(int j = i; j >= k; j--) {
                mark.insert(a[j]);
                val[j] = mark.size();
            }
            // 边界 
            if(k == 1) {
                dp[k][i] = val[1]; continue;
            }
            // 状态转移 
            for(int j = k-1; j < i; j++) {
//              dp[k][i] = max(dp[k][i], dp[k-1][j]+val[j+1]);
                if(dp[k-1][j]+val[j+1] > dp[k][i]) {
                    dp[k][i] = max(dp[k][i], dp[k-1][j]+val[j+1]);
                    tran[k][i] = j;
                }
            }
        }
    }
} 

打印tran 和dp数组,自己摸索规律,可以理清思路。

<think> 根据用户需求,需要提供Codeforces 1617B题目的解题方案。首先,我需要回忆或查找该题目的内容。题目编号1617B对应的是Codeforces Round #767 (Div. 2)的B题,题目名称为"GCD Problem"。 题目描述大致如下:给定一个正整数$n$($n \geq 10$),要求找到三个互不相同的正整数$a$, $b$, $c$,满足以下条件: 1. $a + b + c = n$ 2. $\gcd(a, b) = c$ 注意:$a$, $b$, $c$必须是互不相同的正整数。 解题思路: 1. 由于$c$是$a$和$b$的最大公约数,我们可以设$a = c \cdot d$,$b = c \cdot e$,其中$d$和$e$是互质的整数(即$\gcd(d,e)=1$)。 2. 那么,$a + b + c = c \cdot d + c \cdot e + c = c \cdot (d + e + 1) = n$。 3. 因此,$c$必须是$n$的一个因子。但直接枚举因子可能比较复杂,我们可以尝试构造。 4. 注意到题目要求$a$、$b$、c互不相同,且$c=\gcd(a,b)$,我们可以尝试固定$c=1$,那么问题转化为:找到两个互质的正整数$d$和$e$,使得$d+e+1 = n$(因为$c=1$),即$d+e = n-1$,且$a=d, b=e, c=1$,同时要保证$a,b,c$互不相同。 5. 但是,如果$c=1$,那么$d$和$e$需要满足$d+e=n-1$且$\gcd(d,e)=1$。我们可以选择$d=1$,那么$e=n-2$,此时$\gcd(1, n-2)=1$,所以$a=1, b=n-2, c=1$。但是这里$a=1$和$c=1$相同,违反了互不相同的条件。 6. 因此,我们需要调整。我们可以取$c$为一个不等于1的数?但是题目要求互不相同,同时$c$是$a$和$b$的公约数,而且$c$应该小于$a$和$b$。我们可以尝试取$c$为$n$的某个真因子,但这样可能复杂。 另一种思路: - 由于$n$比较大($n \geq 10$),我们可以尝试令$c$为一个较小的数,比如$c=1$,然后寻找两个互质的数$d$和$e$,使得$d+e=n-1$,且$d,e \geq 2$(这样保证$a,b,c$互不相同)。 - 因为$d$和$e$互质,且$d+e=n-1$,那么我们可以取$d=2$,那么$e=n-3$,此时需要满足$\gcd(2, n-3)=1$。如果$n-3$是奇数,那么$\gcd(2, n-3)=1$(因为2和任何奇数互质)。那么,当$n$是偶数时,$n-3$是奇数吗?注意$n$是偶数时,$n-3$是奇数,所以成立;当$n$是奇数时,$n-3$是偶数,那么$\gcd(2, n-3)=2$(如果$n-3$是偶数),所以不互质。因此,当$n$为奇数时,不能取$d=2$。 改进: - 我们可以取$d$和$e$为两个相邻的数?因为相邻的数互质。设$d$和$e$为两个相邻的正整数,那么$d$和$e$互质,且$d+e=k$(这里$k=n-1$)。那么我们可以取$d = \lfloor k/2 \rfloor$,$e = \lceil k/2 \rceil$,但是要注意相邻的两个整数互质,但这里$d$和$e$不一定相邻,而是和为$k$的两个相邻整数?实际上,任意两个相邻整数互质,所以我们只需要找到两个相邻的整数,使得它们的和为$n-1$?显然,$n-1$是奇数时,可以拆成两个相邻整数(一奇一偶)且互质。但$n-1$为偶数时,相邻整数只能是一奇一偶,但$n-1$为偶数时,两个相邻整数的和是奇数,矛盾?所以当$n-1$是偶数时,我们无法拆成两个相邻整数。 重新考虑:我们只需要两个互质的数,不一定相邻。当$n$为奇数时,我们可以这样构造: 令 $c=1$,则 $d+e = n-1$,且$d,e$互质。我们可以取$d=2$,那么$e=n-3$,但是$n$是奇数,$n-3$是偶数,所以$\gcd(2, n-3)=2$(除非$n-3=2$,即$n=5$,但$n>=10$,所以不行)。那么取$d=3$,$e=n-4$,此时需要$\gcd(3, n-4)=1$。由于$n$是奇数,$n-4$也是奇数,所以不一定互质,但我们可以尝试。 实际上,我们可以取$d$为小于$n-1$的一个较小的数,使得$d$和$e=n-1-d$互质。因为$n-1$是偶数(当$n$为奇数时,$n-1$为偶数),那么我们可以取$d$为奇数?因为两个奇数的和是偶数,而$n-1$是偶数,所以我们可以取两个奇数?但是两个奇数不一定互质。 有一个简单的构造方法: 令 $c=1$,则我们需要将$n-1$拆成两个互质的数$d$和$e$,且$d,e \geq 2$(这样$a,b$至少为2,而$c=1$,所以三者互不相同)。那么,我们可以取$d=2$,$e=n-3$,然后检查$\gcd(2, n-3)$是否为1。当$n$为偶数时,$n-3$是奇数,所以$\gcd(2, n-3)=1$,成立。当$n$为奇数时,$n-3$是偶数,所以$\gcd(2, n-3) \geq 2$,不成立。因此,当$n$是奇数时,我们可以取$d=3$,那么$e=n-4$,此时$n-4$是奇数(因为$n$是奇数,减4还是奇数),那么$\gcd(3, n-4)$可能等于1也可能大于1。但是,由于$n$足够大($n \geq 10$),我们可以确保存在一个较小的$d$使得$d$和$n-1-d$互质。 实际上,我们可以取$d$为小于$n-1$的质数,那么只要$n-1-d$不是$d$的倍数,就互质?但这样不一定,因为互质要求没有共同的质因子。 更简单的构造:取$d$为大于1的奇数,且$d$和$n-1-d$互质。由于$n-1$是偶数(当$n$为奇数时),那么$d$和$n-1-d$都是奇数,且它们相差$2d-(n-1)$?我们可以取$d$为3,然后检查$n-4$是否是3的倍数?如果不是,则$\gcd(3, n-4)=1$。如果是3的倍数,那么我们可以尝试$d=5$,直到找到一个$d$使得$d$和$n-1-d$互质。由于$n-1$是偶数,而$d$是奇数,$n-1-d$也是奇数,所以只要$d$和$n-1-d$没有共同的质因子即可。 但是,题目要求$d$和$e$互质,且$d,e \geq 2$,我们可以固定$d=2$或$d=3$?实际上,我们可以这样: 当$n$是偶数时,取$a=2, b=n-3, c=1$(因为$n$是偶数,$n-3$是奇数,所以$gcd(2, n-3)=1$)。 当$n$是奇数时,取$a=3, b=n-4, c=1$,然后检查$n-4$是否是3的倍数?如果是,那么我们需要调整,比如取$d=4$?但是$d=4$和$e=n-5$不一定互质。实际上,我们可以避免检查:取$d$和$e$分别为$(n-1)/2-1$和$(n-1)/2+1$?这样它们都是奇数,且相邻(差2),那么它们的最大公约数可能是2?但是相邻奇数互质?不对,相邻奇数是指相差2,它们不一定互质(例如15和25,相差10,但可以互质?但15和25不互质)。相邻奇数(相差2)不一定互质,例如9和15,相差6,但都有因子3。 实际上,我们可以这样:因为$n$是奇数,所以$n-1$是偶数。那么我们可以取$d$为2,$e$为$n-3$,但是$n-3$是偶数,所以不互质。那我们取$d$为1?不行,因为$a=c\cdot d$,如果$d=1$,那么$a=c$,但$c=1$,则$a=1$,与$c$相同,而且$b$会等于$n-2$,那么$c=1$,$a=1$,$b=n-2$,这样$a$和$c$重复。 因此,我们改变思路:不固定$c=1$。我们可以取$c$为其他值。 另一种常见的构造: 取$c$为$n$的因子,且$c$较小。例如,我们可以取$c$为$n$除以2的某个因子?但题目要求$c=\gcd(a,b)$,且$a,b,c$互不相同。 观察题目样例:$n=10$,输出$1,2,7$?不对,因为$1+2+7=10$,但$\gcd(1,2)=1$,所以$c=1$,即$a=1,b=2,c=1$?这里$a$和$c$相同,不符合。实际上,题目样例的答案是:$n=10$,输出$3,5,2$,因为$3+5+2=10$,且$\gcd(3,5)=1$?不对,应该是$\gcd(3,5)=1$,而$c=2$?不对,因为$\gcd(3,5)=1$,不等于2。所以重新检查题目。 实际上,题目1617B的样例:输入10,输出4 5 1(因为4+5+1=10,且gcd(4,5)=1,而c=1,满足条件)。但是题目要求$\gcd(a,b)=c$,这里$\gcd(4,5)=1$,所以c=1,满足。 所以正确的构造是:令$c=1$,然后取$a$和$b$为两个互质的数,且$a+b=n-1$,并且$a,b \geq 2$,且$a,b$互不相同。 那么,对于任意$n \geq 10$,我们如何快速找到两个互质的数$a,b$满足$a+b=n-1$且$a,b \geq 2$? - 当$n$是偶数时,$n-1$是奇数,那么我们可以取$a=2$,$b=n-3$(因为$n$是偶数,$n-3$是奇数,所以$a$是偶数,$b$是奇数,且$\gcd(2, n-3)=1$,因为$n-3$是奇数)。 - 当$n$是奇数时,$n-1$是偶数,那么我们可以取$a=3$,$b=n-4$($n$是奇数,$n-4$也是奇数),那么$\gcd(3, n-4)$是否等于1?不一定,比如当$n-4$是3的倍数时,$\gcd(3, n-4)\ge3$。例如$n=13$,$n-4=9$,$\gcd(3,9)=3$,不满足。所以我们需要调整。 对于$n$是奇数的情况,我们可以取$a$为大于1的奇数,且与$b=n-1-a$互质。因为$n-1$是偶数,所以$a$和$b$都是奇数。我们可以从3开始,每次增加2(即取3,5,7,...),直到找到一个$a$使得$\gcd(a, b)=1$。由于$n$比较大($n\ge10$),且$n-1$是偶数,所以$b=n-1-a$也是奇数,且随着$a$增大,$b$减小。由于连续的两个奇数互质?不一定,但我们可以保证在较小的范围内找到。实际上,我们可以取$a$为一个小于$n-1$的质数,那么只要$b$不是这个质数的倍数,就互质。但是$b$可能是这个质数的倍数,所以我们不能保证。 另一种思路:我们取$a$为$(n-1)/2$附近的数。例如,取$a = (n-1)/2 - t$,$b = (n-1)/2 + t$,其中$t$为正整数。那么$a$和$b$都是整数,且关于$(n-1)/2$对称。我们需要$\gcd(a,b)=1$。由于$a$和$b$都是奇数(因为$n-1$是偶数,所以$(n-1)/2$是整数),且它们的差是$2t$,所以它们同奇偶(都是奇数)。而两个奇数互质的概率较大。实际上,我们可以取$t=1$,则$a=(n-1)/2-1$,$b=(n-1)/2+1$,那么有$\gcd(a,b)=\gcd(a, a+2)$(因为$b=a+2$),而$\gcd(a, a+2)=\gcd(a,2)$。由于$a$是奇数(因为$n-1$是偶数,$(n-1)/2$是整数,那么$a$和$b$都是整数,且$a$是奇数,因为$(n-1)/2$是整数,减去1还是整数,而$n$是奇数,$n-1$是偶数,所以$(n-1)/2$是整数,且$a=(n-1)/2-1$是奇数?因为$(n-1)/2$是整数,而$n-1$是偶数,所以$(n-1)/2$可能是奇数也可能是偶数。但$a$和$b$都是整数,且$b=a+2$。$\gcd(a, a+2)=\gcd(a,2)$,因为$a$是奇数(因为$n$是奇数,$n-1$是偶数,而$a=(n-1)/2-1$,由于$(n-1)/2$是整数,而$n-1$是偶数,所以$(n-1)/2$的奇偶性取决于$n$。例如$n=11$,$n-1=10$,$(n-1)/2=5$,则$a=5-1=4$,$b=5+1=6$,但4和6都是偶数,且$\gcd(4,6)=2$。所以不成立。 因此,我们需要更直接的构造。实际上,我们可以取$c$为$n$的一个真因子,但这样构造复杂。我们再看题目,题目要求三个互不相同的正整数,且$c=\gcd(a,b)$,那么$c$一定小于等于$a$和$b$,且$c$至少为1。 实际上,我们可以取$c$为2?那么$a$和$b$都是2的倍数,且$a+b=n-2$。那么我们可以设$a=2, b=n-4$,那么$c=2$,则$a=2, b=n-4, c=2$,这样$a$和$c$相同,不行。所以我们需要$a$和$b$大于2,且是2的倍数,且互质?但两个大于2的偶数不可能互质(因为它们都有因子2)。所以取$c=2$也不行。 我们取$c=3$?那么$a$和$b$都是3的倍数,设$a=3, b=3k$,则$a+b+c=3+3k+3=3(k+2)=n$,所以$n$必须是3的倍数。但$n$不一定是3的倍数,所以不行。 因此,我们回到$c=1$。对于$n$为奇数的情况,我们取$a$和$b$为两个奇数,且和为$n-1$,且互质。我们可以取$a=3$,$b=n-4$,如果$\gcd(3, n-4)=1$,则成立;否则,取$a=5$,$b=n-6$,如果$\gcd(5, n-6)=1$,则成立;以此类推。由于$n$是固定的,且$n$足够大,我们只需要尝试几个较小的奇数就可以找到。实际上,因为$n-1$是偶数,而奇数$a$的范围可以从3到$n-4$,所以总存在一个$a$使得$\gcd(a, n-1-a)=1$?并且由于$n$足够大,我们可以很快找到。 但是,我们能不能不枚举?我们可以取$a$为小于$n-1$的一个质数$p$,那么只要$n-1-p$不是$p$的倍数,那么$\gcd(p, n-1-p)=1$。因为$n-1-p$如果是$p$的倍数,则$n-1-p \equiv 0 \pmod p$,即$n-1 \equiv 0 \pmod p$,所以$p$是$n-1$的因子。那么,我们取一个不是$n-1$的因子的质数$p$,且$p<n-1$,那么一定满足$\gcd(p, n-1-p)=1$。由于$n-1$的因子个数有限,而小于$n-1$的质数很多,所以一定存在。 在竞赛中,我们可以这样构造: - 当$n$是偶数时,取$a=2, b=n-3, c=1$。 - 当$n$是奇数时,取$a$为一个很小的奇质数(比如3),然后检查$b=n-1-a$是否与$a$互质(即检查$\gcd(a, b)=1$),如果成立,则输出$a, b, c=1$;否则,尝试下一个质数(比如5)。由于$n$比较大,很快就能找到。 实际上,我们可以取$a$为3,5,7,...,不一定非要是质数,只要$a$和$b$互质即可。但是,使用质数可以更快地排除倍数关系。我们可以从3开始,每次加2(保证是奇数),然后检查$\gcd(a, n-1-a)=1$,直到找到为止。由于$n$很大,而$n-1$的因子个数很少,所以很快就能找到一个与$n-1$互质的$a$(注意,这里不是要求$a$与$n-1$互质,而是要求$a$与$b=n-1-a$互质,而$\gcd(a, b)=\gcd(a, n-1)$,因为$b=n-1-a$,所以$\gcd(a, b)=\gcd(a, n-1-a)=\gcd(a, n-1)$。因此,我们需要$\gcd(a, n-1)=1$。那么,我们只需要选择一个与$n-1$互质的数$a$($2\leq a \leq n-3$)即可。由于$n-1$是偶数(当$n$为奇数时),所以$a$不能是偶数(否则$\gcd(a, n-1)\ge2$),所以$a$必须是奇数。而$n-1$的质因子是有限的,我们只需要选一个不包含$n-1$的质因子的数。我们可以选择$a$为大于1的最小奇数,使得$\gcd(a, n-1)=1$。例如,$n=15$(奇数),$n-1=14$,14的质因子为2和7。那么我们可以取$a=3$(3和14互质),则$b=14-3=11$,$\gcd(3,11)=1$,所以$a=3, b=11, c=1$。 所以构造方法: 1. 令$c=1$。 2. 若$n$为偶数,则取$a=2$,$b=n-3$(因为$n$为偶数,$n-3$为奇数,$\gcd(2, n-3)=1$)。 3. 若$n$为奇数,则取一个最小的奇数$a$($a\ge3$),使得$\gcd(a, n-1)=1$。由于$n-1$是偶数,且$a$是奇数,所以$\gcd(a, n-1)$只与$n-1$的奇质因子有关。我们可以从3开始,5,7,...递增,直到找到一个与$n-1$互质的$a$,然后令$b=n-1-a$。 注意:$a$必须小于$n-1$,且大于1,并且与$b$不同(因为$b=n-1-a$,而$a$至少为3,$b$至少为$n-1-3$,而$n>=10$,所以$b$至少为6,所以不会相等。同时,$c=1$,与$a,b$不同。 因此,算法步骤: - 读入$n$ - $c=1$ - 如果$n$是偶数: - $a=2$ - $b=n-3$ - 否则($n$是奇数): - $m = n-1$ - $a=3$ - 循环,直到$\gcd(a, m)==1$: $a = a+2$ # 注意,这里每次加2,保持为奇数 - $b = m - a$ - 输出$a, b, c$ 但是,这里有一个问题:当$n$是奇数时,$a$从3开始,然后5,7,...,直到找到与$m$互质的数。由于$m$是偶数,所以$a$只需要是奇数,且与$m$没有共同的奇质因子。而$m$的奇质因子个数有限,所以很快。但是,要确保$a$和$b$都是正整数,且$a,b\ge2$。由于我们取$a$至少为3,那么$b=m-a$,而$m=n-1$,$n\ge10$,$m\ge9$,$a$最大不会超过$m-2$(因为至少留2给$b$),所以$b\ge2$。 但是,在循环中,$a$会一直增加,直到找到满足条件的$a$。由于$m$是偶数,所以一定存在奇数$a$使得$\gcd(a, m)=1$(例如,取$a$为大于$m$的最大质数?不对,我们是从小到大取)。实际上,由于$m$的互质数一定存在,且小于$m$的互质数有很多,所以很快。 但是,我们可以优化:因为$m$的质因子是固定的,我们可以预先知道$m$的质因子,然后跳过这些质因子的倍数。但在竞赛中,直接枚举奇数并检查gcd即可,因为$m$的质因子个数很少,枚举次数不会很多。 另外,注意特殊情况:当$n$为奇数时,$a$不能取$m$的质因子的倍数。例如,$m$有质因子3,5,7等,那么$a$就不能是3,5,7的倍数。但是,我们从小到大取奇数,第一个不被$m$的质因子整除的奇数就是我们要的。由于$m$的质因子集合为$S$,那么最小的不包含$S$中因子的奇数可能很小。 例如,$m=14$(当$n=15$),质因子为2和7(但2不考虑,因为$a$是奇数),那么$a$不能是7的倍数。最小的奇数3,3不是7的倍数,所以取3。 再如,$m=30$($n=31$),质因子有2,3,5(奇数因子为3,5),那么最小的奇数3是3的倍数,跳过;5是5的倍数,跳过;7不是3或5的倍数,所以取7,$b=30-7=23$,$\gcd(7,23)=1$,成立。 因此,我们可以这样实现。 但是,题目要求$c$是正整数,且$a,b,c$互不相同。在我们的构造中,$c=1$,$a$和$b$都大于1,且$a$和$b$不相等(因为$n-1$是偶数,而$a$和$b$都是奇数,且$a \neq b$,因为如果$a=b$,则$a+a=n-1$,即$2a=n-1$,但$n-1$是偶数,所以$a$为整数,但此时$a=(n-1)/2$,那么$b=(n-1)/2$,与$a$相等,但题目要求互不相同。因此,我们取$a$和$b$不相等,而我们的构造中,$a$从3开始,$b=n-1-a$,而$n-1\ge9$,$a$最小为3,$b$最小为$n-1-3\ge6$,所以$a$和$b$不相等。同时,$c=1$,与$a,b$也不相等(因为$a,b\ge3$和$6$,都大于1)。 但是,当$n$为偶数时,$a=2$,$b=n-3$,$c=1$,那么$2$和$1$不相等,$n-3$和$1$也不相等,$2$和$n-3$:当$n=10$时,$b=7$,所以2和7不相等;当$n=12$时,$b=9$,2和9也不相等。所以满足。 因此,我们总结: - 对于任意$n \ge 10$,令$c=1$。 - 如果$n$是偶数,则令$a=2, b=n-3$。 - 如果$n$是奇数,则从$a=3$开始,每次$a$增加2(保持为奇数),直到找到一个$a$使得$\gcd(a, n-1)=1$,然后令$b=n-1-a$。 注意:在$n$为奇数时,$a$的取值范围是$3\le a \le n-4$(确保$b=n-1-a\ge2$,即$a\le n-3$)。由于$n$是奇数且$n\ge10$,$n-1\ge9$,所以$a$从3到$n-4$(奇数)是可行的。 代码实现(C++): ```cpp #include <iostream> #include <cmath> using namespace std; int gcd(int a, int b) { if (b == 0) return a; return gcd(b, a % b); } int main() { int t; cin >> t; while (t--) { int n; cin >> n; int a, b, c = 1; if (n % 2 == 0) { a = 2; b = n - 3; } else { int m = n - 1; // m is even a = 3; // 循环直到找到一个a使得gcd(a, m)==1 while (gcd(a, m) != 1) { a += 2; } b = m - a; } cout << a << " " << b << " " << c << endl; } return 0; } ``` 注意:在$n$为奇数时,$a$从3开始,每次加2,直到找到满足条件的$a$。由于$m$是偶数,而$a$是奇数,所以$\gcd(a, m)$可能大于1,但总存在一个奇数$a$(比如大于$m$的最大质因子)与$m$互质,所以循环会终止。 这个算法的时间复杂度:最坏情况下,$m$的奇质因子很多,但$m$不超过$2\cdot10^5$(题目中$n$的范围?题目没有给出具体范围,但$n\ge10$,且$t$组测试数据,$t$最多多少?题目没给,但一般$t$不超过$10^4$。而内层循环次数:最坏情况下,$m$的互质奇数最小是多少?根据数论,不超过$m$的互质数存在,且最小的大概在$O(\log m)$级别?实际上,最坏情况下,我们枚举的次数最多为$m$的奇质因子个数乘以某个常数,而$m$的质因子个数为$O(\log m)$,所以枚举次数最多几十次。所以总复杂度为$O(t \cdot \log n)$,可以接受。 因此,按照这个方案即可。 输出格式:对于每个测试用例,输出三个整数$a, b, c$,满足条件。 现在,按照用户要求,生成相关问题。 相关问题: 1. 为什么在$n$为奇数时,需要寻找一个与$n-1$互质的奇数$a$? 2. 如何证明在$n$为奇数时,一定存在一个奇数$a$($3\le a\le n-4$)满足$\gcd(a, n-1)=1$? 3. 除了$c=1$的构造,还有没有其他构造方法? 4. 如果$n$小于10,题目是否有解? </think>### Codeforces 1617B "GCD Problem" 解题方案 #### 题目描述 给定一个整数 $n$($n \geq 10$),要求找到三个**互不相同**的正整数 $a, b, c$,满足以下条件: 1. $a + b + c = n$ 2. $\gcd(a, b) = c$ #### 解题思路 1. **核心观察**: 由于 $\gcd(a, b) = c$,可设 $a = c \cdot d$,$b = c \cdot e$,其中 $d$ 和 $e$ 互质($\gcd(d, e) = 1$)。 则原条件转化为: $$ c \cdot d + c \cdot e + c = n \implies c \cdot (d + e + 1) = n $$ 因此,$c$ 必须是 $n$ 的因子。但直接枚举因子较复杂,可通过构造简化。 2. **关键构造**: 固定 $c = 1$,则问题简化为: - $d + e = n - 1$ - $\gcd(d, e) = 1$ - $d, e \geq 2$(确保 $a, b, c$ 互不相同) 3. **分类讨论**: - **当 $n$ 为偶数时**: $n - 1$ 是奇数,取 $d = 2$,$e = n - 3$。 此时 $\gcd(2, n - 3) = 1$(因为 $n - 3$ 是奇数),且 $a = 2, b = n - 3, c = 1$ 互不相同。 - **当 $n$ 为奇数时**: $n - 1$ 是偶数,需寻找奇数 $d \geq 3$ 使得 $\gcd(d, n - 1) = 1$(因为 $\gcd(d, e) = \gcd(d, n - 1)$)。 从 $d = 3$ 开始,每次增加 2(保持奇数),直到找到满足条件的 $d$,则 $e = n - 1 - d$。 #### 代码实现(C++) ```cpp #include <iostream> using namespace std; int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); } int main() { int t; cin >> t; while (t--) { int n; cin >> n; int a, b, c = 1; if (n % 2 == 0) { a = 2; b = n - 3; } else { int m = n - 1; a = 3; while (gcd(a, m) != 1) { a += 2; } b = m - a; } cout << a << " " << b << " " << c << endl; } return 0; } ``` #### 算法分析 - **正确性**: - $n$ 为偶数时,$a=2, b=n-3, c=1$ 满足 $\gcd(2, n-3)=1$ 且互不相同。 - $n$ 为奇数时,由于 $n-1$ 的互质数一定存在,且奇数 $d$ 的枚举范围 $[3, n-4]$ 足够大,必能找到解。 - **时间复杂度**: - 外层循环 $t$ 次(测试用例数),内层循环最多 $O(\log n)$ 次(与 $n-1$ 的质因子个数相关)。 - 整体复杂度 $O(t \log n)$,满足竞赛要求。 #### 示例 - **输入**:$n = 10$(偶数) **输出**:$a=2, b=7, c=1$($2+7+1=10$,$\gcd(2,7)=1$) - **输入**:$n = 15$(奇数) **输出**:$a=3, b=11, c=1$($3+11+1=15$,$\gcd(3,11)=1$) [^1]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值