2019CCPC-江西省赛-Worker

题目

Avin meets a rich customer today. He will earn 1 million dollars if he can solve a hard problem. There are n warehouses and m workers. Any worker in the i-th warehouse can handle ai orders per day. The customer wonders whether there exists one worker assignment method satisfying that every warehouse handles the same number of orders every day. Note that each worker should be assigned to exactly one warehouse and no worker is lazy when working.
Input
The first line contains two integers n (1 ≤ n ≤ 1, 000), m (1 ≤ m ≤ 1018). The second line contains n integers. The i-th integer ai (1 ≤ ai ≤ 10) represents one worker in the i-th warehouse can handle ai orders per day.
Output
If there is a feasible assignment method, print “Yes” in the first line. Then, in the second line, print n integers with the i-th integer representing the number of workers assigned to the i-th warehouse.
Otherwise, print “No” in one line. If there are multiple solutions, any solution is accepted.
Sample Input
2 6
1 2
2 5
1 2
Sample Output
Yes
4 2
No

题目大意

第一行输入n,m表示仓库数和总工人数。然后在第二行输如n个数分别表示从第1号仓库到第n号仓库每个工人可以处理的订单数量。即工人的能力是由在哪个仓库决定的,固定的仓库工人分配过去就会处理其仓库对应的每个工人可以处理的订单数量。问你m个工人都要分配完,能不能找到一种方案使每个仓库处理的订单数相同。比如第一组测试用例,2 6表示两个仓库六个工人,1表示第一个仓库一个工人可以处理1订单,2表示第一个仓库一个工人可以处理2订单。答案 Yes表示存在分配情况成立,4表示给第一个仓库分配四个即其仓库可以处理14订单,2表示给第二个仓库分配两个其仓库可以处理22订单。

解题思路

问题简化,设第i号仓库单工人能处理订单数为ai(1<=i<=n),无论如何分配第i号仓库所有工人能处理的订单数si一定为ai的整数倍,即 si=k*ai(人没有半个 )。如何求一个数能使他们所有仓库si相等呢?求所有ai的最小公倍数,即所有仓库至少要处理所有ai的最小公倍数。当然每个仓库要相等,也可以处理最小公倍数的正整数倍数。求出最小公倍数后依次除以每个仓库的单工人处理数得到在最小公倍数情况下每个仓库的工人数,求和的总共人数。我们说可以是最小公倍数的倍数,所以只要m总工人数是求得最小公倍数时人数的倍数即可。最后每个仓库输出工人数就是m除以最小公倍数需要的人数(几个,几倍最小公倍数)*当初求得最小公倍数时的仓库人数。

具体代码(详细注释)

#include<iostream>
using namespace std;

long long gcd(long long a, long long b)//计算a和b的最大公约数
{
    return (b == 0) ? a : gcd(b, a % b);
}

long long Gbs(long long  a, long long b)//计算a和b的最小公倍数
{
    return (a * b) / gcd(a, b);//最小公倍数等于二者乘积除以二者最大公约数
}

int main()
{
    int n;
    long long m;//m<=1e18,属于长整型范围
    while (~scanf("%d %lld", &n, &m))//读入n和m
    {
        long long a[1020] = {};//定义数组存储每个仓库独特的单个工人工作量
        long long b = 1;   //使用b来存储所有仓库单工人工作量的最小公倍数
        for (int i = 0; i < n; i++)//从1到n,求最小公倍数
        {
            scanf("%d",&a[i]);
            b = Gbs(b, a[i]);
        }//最后b就是整个数组(所有仓库)的最小公倍数
        long long sum = 0;//使用sum记录所有仓库都生成最小公倍数任务量时的总使用工人数
        for (int i = 0; i < n; i++)//从0到n
        {
            a[i] = b / a[i];//计算每个仓库的工人数b/a[i]再使用a[i]记住(因为原来的a[i]已经不需要了)
            sum += a[i]; //计求和得到 所有仓库都生成最小公倍数任务量时的总使用工人数
        }//当各仓库生产量相同时,此生产量必定是最小公倍数的正整数倍,所以人数也是sum的正整数倍
        if (m % sum == 0) {//如果工人可以是sum的整数倍
            printf("Yes\n");//则可以成立各仓库工作量相同并且工人分配完
            for (int i = 0; i < n; i++)
            {//则输入每个仓库的工人数量,a[i]记录了工作量为最小公倍数时每个仓库的工人数
                printf("%lld", a[i] * (m / sum));
                if(i<=n-2)printf(" ");
                else cout<<endl;
            }//m是sum的多少倍(即每个仓库生产多少个最小公倍数),那么每个仓库的人数也是a[i]的多少倍
        }
        else printf("No\n");//否则m不是sum的整数倍则不可成立
    }
    return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

仰望—星空

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

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

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

打赏作者

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

抵扣说明:

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

余额充值