非常有趣的一道贪心题。考试期间我是毫无思路,然后今天看作者的题解,哇,真玄学。下面我大概就把作者的题解思路说一下,然后誊写一遍作者的代码
题意大概是这样的,一帮人选座位,要求不同组的不能坐在一起。每一行的座位构成都是这样的:
那么显然12 34 45 56 78是邻位。现在给你各组的人数,问能不能满足条件。
好,首先为了粉碎一些天真的想法,我们先举几个蛇皮走位:
1行,2个组,每组4个,方法是这样的:
又如,1行4个组,是2 2 2 1,方法:
那么作者本人是怎么想的呢?
首先我们将座椅分为两种,一种是4人座,一种是2人座。一共有n排,就先将n排分为n个4人座与2n个2人座。
好,那么假设某一组有k个人。我们优先让他们坐在4人座上,如果没有空余的4人座,就让他们去坐2人座。为什么这样排?因为4人座没有两人座灵活,如果某一组有3个人,那么分在一个4人座、2个2人座是等价的;而如果两个组人数分别为为2,2,分两个两人座是允许的,但没办法放四人座;如果两个组人数分别为1,1,1个4人座与2个2人座也是等价的。所以我们发现,4人座安排上没有两人座方便,所以我们优先四人座。
因此我们的第一步就是遍历让k-4,如果没有两人座就-2。当然,这个过程如果4人座和2人座都满了,那直接超载,别多想。而遍历的终止时机,则是k<=2.现在我们剩下的人只有两种情况:1个人成1组,2个人成1组。
对于两人组的处置,我们优先放2人座。因为如果放到4人座上,就会使得4人座只能放一个人。如果2人座满了,就将4人座拆成一个两人座和一个单人座。实在不行先将两个人拆成两个单人,这样,我们消灭了所有的2人,只剩下一堆的单人成组和一堆座。一个四人座可以充当两个单人座,所以最后的判断就是比较单人剩余数量与(2*4人座数量+2人座数量+单人座数量),比较一下就可以了。
总结一下这个结果是如何得出的。
- 将每个组的人优先分到4人座上,不够的再分到两人座上,直到剩余1个或2个人
- 将每个2人组优先分到2人座上,否则将4人座拆为1双1单,否则拆成两个单人
- 比较最后剩余的可座的座位数与单人的剩余量。
那么代码就呼之欲出了:
#include <bits/stdc++.h>
using namespace std;
#define maxn 10003
int twose,fouse,onese;
int cou[4];
int main(){
int n,k;
cin>>n>>k;
twose=n<<1,fouse=n;
for(int i=0;i<k;++i){
int p;cin>>p;
while(p>=3){//步骤1
if(fouse>0)
p-=4,--fouse;
else if(twose>0)
p-=2,--twose;
else{
cout<<"NO"<<endl;
return 0;
}
}
if(p>0) cou[p]++;
}
while(cou[2]){//步骤2
if(twose>0)
--cou[2],--twose;
else if(fouse>0)
--cou[2],--fouse,++onese;
else
--cou[2],cou[1]+=2;
}
if(cou[1]<=onese+twose+2*fouse) cout<<"YES"<<endl;//步骤3
else cout<<"NO"<<endl;
return 0;
}
贪心好难啊qwq