C/C++排队打饭

C/C++排队打饭

题目描述
每天中午下课铃一打,同学们为了能尽早吃上饭,不要排那么长时间的队,都像狼一样冲向食堂,校领导看到这种情况很是担忧,因为学生们这样狂奔很危险,所以就要求必须等所有同学都来到食堂才能开始打饭,并且把排队打饭的顺序固定下来,这样谁都不用抢了。
学校里一共有N(1<=N<=100)个学生,每个学生打饭所需时间也是已知的,为了不让学生排队等得心烦,要求设计一个排队顺序使得所有学生的等待时间之和最小,等待时间为从开始排队到开始打饭所需的时间,所以第一个学生的等待时间为0。
为了给同学们新鲜感,领导想在保证等待时间之和最小的情况下尽可能多地改变排队顺序,所以想知道一共有多少种排队顺序?你能帮忙吗?

输入
第一行输入一个整数N(1<=N<=100),表示学生人数。
第二行输入N个正整数(在1到100之间),中间用空格隔开,表示每个学生打饭所需要的时间。

输出
一行输出两个整数,第一个数表示最小的等待时间之和,第二个整数表示在保证等待时间之和最小的前提下的排队方案数,第二个数可能很大,所以输出方案总数对2011的余数。

样例输入
4
1 2 1 2

样例输出
7 4

数据范围限制

提示
有4种排队方案分别是1 3 2 4、3 1 2 4、1 3 4 2、3 1 4 2,等待时间为7。

这道题乍一看,有点棘手,但一细想,发现这其实就是一个打水问题与乘法原理的集合。
第一个数据相信知道打水问题的朋友都清楚,关键在在他打饭时他自己不用等。
而第二个数据呢,很多人第一反应是:枚举,暴力。但我是怎么都不知道该如何暴力枚举。
而我们发现,如果想让方案多、时间小唯一的办法就是交换两个相同值,数组元素虽然值还是一样,但位置不一样了呀。如样例提示(提示的数字是下标位置)再联想乘法原理,所有问题便迎刃而解。
现在读入元素时将每个值像这样存起来:
cin>>a[i];
c[a[i]]++;
这样存起来的是每个元素出现的次数,而且保证0<a[i]<=100,所以定义c[101]就够了,
存进去之后我们在下面写一个1~100的循环i,访问c[i];如果c[i]!=0(有人的打饭时间是i),就从
1~c[i]循环j,并将一个每次循环都初始化为1的x变量累乘
x*=j;
并且x%=2011
根据乘法原理,在j循环外面答案乘等于x。
输出答案

把代码写出来是这:

#include<iostream>
#include<algorithm>
using namespace std;
int x,n,a[101],c[101],asn=1,tim;
int main()
{
	cin>>n;
	for(int i=0;i<n;i++)
	{
		cin>>a[i];
		c[a[i]]++;//标记c
	}
	sort(a,a+n);//排序
	x=n;
	for(int i=0;i<n-1;i++)
	{
		x--;
		tim+=x*a[i];//算第一个数据tim
	}
	for(int i=1;i<=100;i++)//循环c数组
	{
		x=1;//赋值1
		if(c[i]!=0)//如果有人的打饭时间是i
		{
			for(int j=1;j<=c[i];j++)//累乘
			{
				x*=j;
				x%=2011;//取模
			}
		}
		asn*=x;//累乘答案
		asn%=2011;//取模
	}
	cout<<tim<<' '<<asn;//输出
	return 0;
}

这题有点难度,看一遍没明白就再看几遍,最后别忘了点赞!❤

  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值