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;
}
这题有点难度,看一遍没明白就再看几遍,最后别忘了点赞!❤