2020 NOI online 入门组第一题题解--zhengjun

题目描述

小明的班上共有 n n n 元班费,同学们准备使用班费集体购买 3 3 3 种物品:

圆规,每个 7 7 7 元。
笔,每支 4 4 4 元。
笔记本,每本 3 3 3 元。
小明负责订购文具,设圆规,笔,笔记本的订购数量分别为 a , b , c a,b,c a,b,c,他订购的原则依次如下:

  1. n n n 元钱必须正好用光,即 7 a + 4 b + 3 c = n 7a+4b+3c=n 7a+4b+3c=n
  2. 在满足以上条件情况下,成套的数量尽可能大,即 a , b , c a,b,c a,b,c 中的最小值尽可能大。
  3. 在满足以上条件情况下,物品的总数尽可能大,即 a + b + c a+b+c a+b+c 尽可能大。

请你帮助小明求出满足条件的最优方案。可以证明若存在方案,则最优方案唯一。

输入格式

输入仅一行一个整数,代表班费数量 n n n

输出格式

如果问题无解,请输出 − 1 -1 1

否则输出一行三个用空格隔开的整数 a , b , c a, b, c a,b,c,分别代表圆规、笔、笔记本的个数。

输入输出样例
输入 #1 复制
1
输出 #1 复制
-1
输入 #2 复制
14
输出 #2 复制
1 1 1
输入 #3 复制
33
输出 #3 复制
1 2 6
说明/提示
样例输入输出 3 解释

a = 2 , b = 4 , c = 1 a=2,b=4,c=1 a=2,b=4,c=1 也是满足条件 1 , 2 1,2 1,2 的方案,但对于条件 3 3 3,该方案只买了 7 7 7 个物品,不如 a = 1 , b = 2 , c = 6 a=1,b=2,c=6 a=1,b=2,c=6 的方案。

数据规模与约定
  • 对于测试点 1 ∼ 6 1 \sim 6 16,保证 n ≤ 14 n \leq 14 n14
  • 对于测试点 7 ∼ 12 7 \sim 12 712,保证 n n n 14 14 14 的倍数。
  • 对于测试点 13 ∼ 18 13 \sim 18 1318,保证 n ≤ 100 n \leq 100 n100
  • 对于 100 % 100\% 100% 的数据,保证 0 ≤ n ≤ 1 0 5 0 \leq n \leq 10^5 0n105

思路

这么简单的一道题,考试时竟然没有注意到一个细(kēng)节(diǎn),实在是失策失策

好了,进入正题

说白了,就是求一元三次方程的非负整数解(其他的特殊要求先不管)

首先,我们要先判断 7 a + 4 b + 3 c = n 7a+4b+3c=n 7a+4b+3c=n 是否可以有非负整数解。

我们发现这个方程中 : a a a 的系数就等于 b b b 的系数加 c c c 的系数,即 7 = 3 + 4 7=3+4 7=3+4

所以,要判断是否有非负整数解,只要判断二元一次方程 3 x + 4 y = n 3x+4y=n 3x+4y=n 是否有非负整数解就可以了。

然后我们发现 g c d ( 3 , 4 ) = 1 gcd(3,4)=1 gcd(3,4)=1 (   3 , 4 (\ 3,4 ( 3,4 的最大公因数是 1   ) 1\ ) 1 ), 也就是说,只要 n n n 大于 7 7 7 并且 n n n 1 1 1 的倍数,这个方程就一定有非负整数解。

例如 9 x + 12 y = n 9x+12y=n 9x+12y=n g c d ( 9 , 12 ) = 3 gcd(9,12)=3 gcd(9,12)=3,所以,只要 n n n 大于 21 21 21 并且是 3 3 3 的倍数,那么这个方程就一定有非负整数解

你还可以自己去举更多的例子。

这样,我们就可以判断 7 x + 4 b + 3 c = n 7x+4b+3c=n 7x+4b+3c=n 这个方程是否有非负整数解了( 0 0 0 7 7 7 的自己可以算(còu),结果就是只有 1 1 1 2 2 2 5 5 5 没有非负整数解)。

然后,就是整道题目的核心

先说明,我讲的不是暴力,是分类讨论(加上一点数形结合、方程以及类比的思想)

分类讨论:关于 n   m o d   7 n\ mod\ 7 n mod 7 的分类 ( 以下的分类都是在由负整数解的情况下所述的 )

A_zjzj

比如说这幅图。

n = 7 k + x   (   0 ≤ x < 7   ) n=7k+x\ (\ 0\leq x\lt7\ ) n=7k+x ( 0x<7 )

  1. n   m o d   7 = 0 n\ mod\ 7=0 n mod 7=0 时,最优的方案就应该是把 k k k 分成两份,一份分给 7 7 7 ,另一份分给 3 , 4 3,4 3,4,如果不可以平均分,那么为了让买的总数最大,就应该把剩下的 1 1 1 7 7 7 3 , 4 3,4 3,4
  2. n   m o d   7 = 1 n\ mod\ 7=1 n mod 7=1 时,因为 3 3 3 4 4 4 无法拼出 1 1 1 ,所以我们要拆开一个 7 7 7 ,拿出来和 1 1 1 一起用两个 4 4 4 拼出,但是,如果可以拆出来两个 7 7 7 的话,那么就可以拼出五个 3 3 3 ,却少拼了一个 3 3 3 和一个 4 4 4 ,还是比前一种方案优,所以,只要可以拆出来两个 7 7 7 ,就要分给 3 3 3 ,否则就拆一个出来分给 4 4 4
  3. n   m o d   7 = 2 n\ mod\ 7=2 n mod 7=2 时,就要拿出一个 7 7 7 拼三个 3 3 3 ,如果拆两个的话,可以算一下,没有拆一个的方案优。
  4. n   m o d   7 = 3 n\ mod\ 7=3 n mod 7=3 时,那 x x x 就直接给 3 3 3
  5. n   m o d   7 = 4 n\ mod\ 7=4 n mod 7=4 时, x x x 就直接给 4 4 4
  6. n   m o d   7 = 5 n\ mod\ 7=5 n mod 7=5 时,就要加一个 7 7 7 ,得到 12 12 12,那么为了让买的总数最多,应该把这 12 12 12 都给 3 3 3 是最优的。
  7. n   m o d   7 = 6 n\ mod\ 7=6 n mod 7=6 时, x x x 就都给 3 3 3 就可以了

所以公式就是:

提示:一下所述的除法都是整除

  1. n   m o d   7 = 0 n\ mod\ 7=0 n mod 7=0 时, a = b = c = n ÷ 7 ÷ 2 = n ÷ 14 a=b=c=n\div7\div2=n\div14 a=b=c=n÷7÷2=n÷14
  2. n   m o d   7 = 1 n\ mod\ 7=1 n mod 7=1 时,如果 n ≤ 8 n\le8 n8 a = ( n ÷ 7 − 1 ) ÷ 2   ,   b = n ÷ 7 − a − 1 + 2 = n ÷ 7 − a + 1   ,   c = n ÷ 7 − a − 1 a=(n\div7-1)\div2\ ,\ b=n\div7-a-1+2=n\div7-a+1\ ,\ c=n\div7-a-1 a=(n÷71)÷2 , b=n÷7a1+2=n÷7a+1 , c=n÷7a1,如果 n > 8 n>8 n>8 a = ( n ÷ 7 − 2 ) ÷ 2 = n ÷ 14 − 1   ,   b = n ÷ 7 − a − 2 + 2 = n ÷ 7 − a   ,   c = n ÷ 7 − a − 2 a=(n\div7-2)\div2=n\div14-1\ ,\ b=n\div7-a-2+2=n\div7-a\ ,\ c=n\div7-a-2 a=(n÷72)÷2=n÷141 , b=n÷7a2+2=n÷7a , c=n÷7a2
  3. n   m o d   7 = 2 n\ mod\ 7=2 n mod 7=2 时, a = ( n ÷ 7 − 1 ) ÷ 2   ,   b = n ÷ 7 − a − 1   ,   c = n ÷ 7 − a − 1 + 3 = n ÷ 7 − a + 2 a=(n\div7-1)\div2\ ,\ b=n\div7-a-1\ ,\ c=n\div7-a-1+3=n\div7-a+2 a=(n÷71)÷2 , b=n÷7a1 , c=n÷7a1+3=n÷7a+2
  4. n   m o d   7 = 3 n\ mod\ 7=3 n mod 7=3 时, a = b = n ÷ 7 ÷ 2 = n ÷ 14   ,   c = n ÷ 7 ÷ 2 + 1 = n ÷ 14 + 1 a=b=n\div7\div2=n\div14\ ,\ c=n\div7\div2+1=n\div14+1 a=b=n÷7÷2=n÷14 , c=n÷7÷2+1=n÷14+1
  5. n   m o d   7 = 4 n\ mod\ 7=4 n mod 7=4 时, a = c = n ÷ 7 ÷ 2   ,   b = n ÷ 7 ÷ 2 + 1 a=c=n\div7\div2\ ,\ b=n\div7\div2+1 a=c=n÷7÷2 , b=n÷7÷2+1
  6. n   m o d   7 = 5 n\ mod\ 7=5 n mod 7=5 时, a = ( n ÷ 7 − 1 ) ÷ 2   ,   b = n ÷ 7 − a − 1   ,   c = n ÷ 7 − a − 1 + 4 = n ÷ 7 − a + 3 a=(n\div7-1)\div2\ ,\ b=n\div7-a-1\ ,\ c=n\div7-a-1+4=n\div7-a+3 a=(n÷71)÷2 , b=n÷7a1 , c=n÷7a1+4=n÷7a+3
  7. n   m o d   7 = 6 n\ mod\ 7=6 n mod 7=6 时, a = b = n ÷ 7 ÷ 2   ,   c = n ÷ 7 ÷ 2 + 2 a=b=n\div7\div2\ ,\ c=n\div7\div2+2 a=b=n÷7÷2 , c=n÷7÷2+2

可能有点看不太清,换表格

x的值a的值b的值c的值
n%7=0n÷14n÷7-n÷14n÷7-n÷14
n%7=1(n÷7-1)÷2n÷7-(n÷7-1)÷2+1n÷7-(n÷7-1)÷2-1
n%7=2,n≤8(n÷7-1)÷2n÷7-(n÷7-1)÷2-1n÷7-(n÷7-1)÷2
n%7=2,n>8n÷14-1n÷7-n÷14-1n÷7-n÷14+4
n%7=3n÷14n÷7-n÷14n÷7-n÷14+1
n%7=4n÷14n÷7-n÷14+1n÷7-n÷14
n%7=5(n÷7-1)÷2n÷7-(n÷7-1)÷2-1n÷7-(n÷7-1)÷2+3
n%7=6n÷14n÷7-n÷14n÷7-n÷14+2

注意,在所有的 b , c b,c b,c 中的 n ÷ 7 − n ÷ 14 n\div7-n\div14 n÷7n÷14 绝对不可以改成 n ÷ 14 n\div14 n÷14 ,因为是整除

好了,不多说了,细(kēng)节(diǎn)不少

代码

#include<bits/stdc++.h>
using namespace std;
int n;
int main(){
    scanf("%d",&n);
    if(n==1||n==2||n==5)
        printf("-1");
    else if(n%7==0)
    	printf("%d %d %d",n/14,n/7-n/14,n/7-n/14);
    else if(n%7==1)
        if(n>8)
            printf("%d %d %d",n/14-1,n/7-n/14-1,n/7-n/14+4);
        else
            printf("%d %d %d",(n/7-1)/2,n/7-(n/7-1)/2+1,n/7-(n/7-1)/2-1);
    else if(n%7==2)
        printf("%d %d %d",(n/7-1)/2,n/7-(n/7-1)/2-1,n/7-(n/7-1)/2+2);
    else if(n%7==3)
        printf("%d %d %d",n/14,n/14,n/14+1);
    else if(n%7==4)
        printf("%d %d %d",n/14,n/7-n/14+1,n/7-n/14);
    else if(n%7==5)
        printf("%d %d %d",(n/7-1)/2,n/7-(n/7-1)/2-1,n/7-(n/7-1)/2+3);
    else if(n%7==6)
        printf("%d %d %d",n/14,n/7-n/14,n/7-n/14+2);
	return 0;
}

谢谢–zhengjun

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

A_zjzj

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值