题目链接
http://codeforces.com/contest/839/problem/B
题目大意
给你k组士兵, 每组有ai人, 你有n排座位, 每排座位如下图所示
即{1, 2}, {3, 4}, {4, 5}, {5, 6}, {7, 8}这些座位相邻
问你士兵能否都坐下且保证不同组的士兵不坐在相邻座位上
(题目保证人数<座位数)
思路
这题我们可以用贪心做, 一下把3~6座简称4座, 1~2 和 7~8简称2座
贪心策略
1.如果一组人能把4座的座位坐满, 那就尽量用4座的座位给他们坐,4座的没了就用2座的
2.这样处理完了之后每只队伍人数就只剩下1, 2, 3这三种情况了
然后我们再安排3个人的队伍入座, 同样优先选择4座的, 然后2座的
3.安排2个人的队伍入座, 这时我们优先选择2座的再选择4座的
4.安排一个人的队伍入座, 这时就不用考虑先座哪个了, 能坐下就好了
证明
- 对于4座和2座的比较, 首先一排中2座有两个, 所以它能坐下的人数和四座无区别, 但是4座的无法坐下两只两个人的队伍, 所以在第一步2座相比4座珍贵, 所以优先选择4座的
- 同上
- 这里2座和4座的优先级其实差不多orz
- 没了
细节
- 两个人的队伍坐到四座之后其实还能空出一个座位给一个人坐
- 三个人的队伍可以拆成2 + 1, 也就是两个人坐在2座, 一个人去4座
- 两个人的队伍可以拆成1 + 1, 然后占两个4座
代码
#include<bits/stdc++.h>
using namespace std;
int a[105];
int cnt[5];
int main()
{
int n, k;
scanf("%d%d", &n, &k);
for(int i=1; i<=k; ++i)
scanf("%d", a+i);
sort(a+1, a+k+1);
bool flag = true;
int top = k, c2 = 2*n, c4 = n, c1 = 0;
for(int i=k; i>=1; --i)
{
if(a[i] < 4) ++cnt[a[i]];
else if(c4 == 0)
{
c2 -= a[i]/2;
++cnt[a[i]%2];
}
else if(c4 - a[i]/4 >= 0)
{
c4 -= a[i]/4;
++cnt[a[i]%4];
}
else if(c4 - a[i]/4 < 0)
{
a[i] -= c4 * 4;
c4 = 0;
c2 -= a[i]/2;
++cnt[a[i]%2];
}
}
if(c2 < 0 && c4 == 0) puts("NO");
else
{
for(int i=0; i<cnt[3]; ++i)
{
if(c4 - 1 >= 0) --c4;
else c2 -= 2;
}
for(int i=0; i<cnt[2]; ++i)
{
if(c2 - 1 >= 0) --c2;
else
{
if(c4 - 1 >= 0)
{
--c4;
++c1;
}
else c1 -= 2;
}
}
int sum = 0;
if(c1 > 0) sum += c1;
if(c2 > 0) sum += c2;
if(c4 > 0) sum += c4 * 2;
if(c1 < cnt[1] && c2 <= 0 && c4 <= 0)puts("NO");
else if(sum >= cnt[1] && c2 >= 0 && c4 >= 0 && c1 >= 0)
puts("YES");
else puts("NO");
}
return 0;
}
膜拜
其实很多情况可以合并, 这样可以缩很多行, 少很多if, 再用一些奇妙(guai)的语法规则, 就可以变成下面这样
#include<iostream>
int i,n,k,a,s,j;
main(){
for(std::cin>>n>>k;i<k;i++)std::cin>>a,a%2?a++,j++:0,s+=a;
std::cout<<(s>8*n||s==8*n&&k==4*n&&j<n?"NO":"YES");
}
Orz