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

题目描述

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

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

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

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

输入格式

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

输出格式

如果问题无解,请输出 \(-1\)

否则输出一行三个用空格隔开的整数 \(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\) 也是满足条件 \(1,2\) 的方案,但对于条件 \(3\),该方案只买了 \(7\) 个物品,不如 \(a=1,b=2,c=6\) 的方案。

数据规模与约定
  • 对于测试点 \(1 \sim 6\),保证 \(n \leq 14\)
  • 对于测试点 \(7 \sim 12\),保证 \(n\)\(14\) 的倍数。
  • 对于测试点 \(13 \sim 18\),保证 \(n \leq 100\)
  • 对于 \(100\%\) 的数据,保证 \(0 \leq n \leq 10^5\)

思路

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

好了,进入正题

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

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

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

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

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

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

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

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

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

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

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

A_zjzj

比如说这幅图。

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

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

所以公式就是:

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

  1. \(n\ mod\ 7=0\) 时,\(a=b=c=n\div7\div2=n\div14\)
  2. \(n\ mod\ 7=1\) 时,如果 \(n\le8\)\(a=(n\div7-1)\div2\ ,\ b=n\div7-a-1+2=n\div7-a+1\ ,\ c=n\div7-a-1\),如果 \(n>8\)\(a=(n\div7-2)\div2=n\div14-1\ ,\ b=n\div7-a-2+2=n\div7-a\ ,\ c=n\div7-a-2\)
  3. \(n\ mod\ 7=2\) 时,\(a=(n\div7-1)\div2\ ,\ b=n\div7-a-1\ ,\ c=n\div7-a-1+3=n\div7-a+2\)
  4. \(n\ mod\ 7=3\) 时,\(a=b=n\div7\div2=n\div14\ ,\ c=n\div7\div2+1=n\div14+1\)
  5. \(n\ mod\ 7=4\) 时,\(a=c=n\div7\div2\ ,\ b=n\div7\div2+1\)
  6. \(n\ mod\ 7=5\) 时,\(a=(n\div7-1)\div2\ ,\ b=n\div7-a-1\ ,\ c=n\div7-a-1+4=n\div7-a+3\)
  7. \(n\ mod\ 7=6\) 时,\(a=b=n\div7\div2\ ,\ c=n\div7\div2+2\)

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

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

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

好了,不多说了,细(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

posted @ 2022-06-10 19:03  A_zjzj  阅读(48)  评论(0编辑  收藏  举报