模拟也能出奇迹
Description
有N组学生,给出初始时每组中的学生个数,再给出每组学生人数的上界R和下界L(L≤R),每次你可以在某组中选出一个学生把他安排到另外一组中,问最少要多少次才可以使N组学生的人数都在[L,R][L,R]中.
Data
Input
第一行一个整数N,表示学生组数; n≤50
第二行N个整数,表示每组的学生个数;
第三行两个整数 L,R,表示下界和上界.
Output
一个数,表示最少的交换次数,如果不能满足题目条件输出-1.
Sample Input
2
10 20
10 15
Sample Output
5
思路
用某奆的话说:
这道题,出乎意料的简单!
好像每个人都说过这句话 ?
好了开始正题:
铺垫
乍一看这道题可能难以下手,但是这可是[普及-]的难度啊!做不出来岂不是自损名声?
于是可以仔细观察,为什么这道题难以下手
模拟学生的流动,可能会花费大量时间.
既要考虑人员流动最小,又要保证各组人员始终在[L,R]以内.
想想就麻烦(不做了)
但是,真的需要这样模拟吗?
接近
排座位的时候,需要按甲乙丙丁……
这个时候,所有人的都是有不同的.
换句话说,这是一个排列,是按 ABDEC… 这样的顺序安排的
但是本题的人员是“一视同仁”,都是 AAAAA…
所以,一定要考虑每个人?
想到这里,豁然开朗.
AC我来了!
预先规定:
我们把[N*L,N*R]之间的总和S成为合法总和
先判断不合法(-1)的情况:
- 当总和大于合法总和时,就是不合法的.
- 当总和小于合法总和时,就是不合法的
没错就是这么简单
可以反证,在这个总和区间 的都可以被分配好.
那么:我们可以对Ai 进行分析:
- 如果Ai 大于等于L且小于等于R, 不需要处理.
- 如果Ai大于R,那么因为总和S在合法总和区间内,所以总可以找到一种方案,使原本在[L,R]之间的Ai保持在[L,R]内,并且填补那些小于L的Ai.(比如直接填补)
- 如果Ai小于L,逻辑同2.
所以,我们只需判断有多少个Ai>R,多少个Ai<L,然后将这些组数的总和比较,输出较大值即可.?
具体问题还需读者自行实现.
Code
int n;
int a[N];
int L,R,A,B,S;
int main()
{
for (int i=1;i<=n;i++) S+=a[i];
cin >>L>>R;
for (int i=1;i<=n;i++)
if (a[i]>R) A+=(a[i]-R);
else if (a[i]<L) B+=(L-a[i]);
if (S>R*n||S<L*n) cout<<"-1"<<endl;
else cout<<max(A,B)<<endl;
}
感谢奆老关注qwq ?