Codeforces Round #469 (Div. 2) F. Curfew (贪心)

传送门:http://codeforces.com/contest/950/problem/F


题目大意:

  n个寝室,2个老师查寝,一个按1、2、3……的顺序,另一个按n、n-1、n-2……的顺序。若n为偶数则2个老师每人检查一半;为奇数则中间的寝室第一个老师检查。老师只检查人数,而不管到底是谁,当检查完一个寝室后,老师会把这个寝室的门锁了。

  每个寝室应该有b个人,一开始这n*b个人分布在不同的寝室里。在检查时,每个人有三种选择:①待在该寝室不动;②移动到d范围内的寝室里(本来在i寝室,则可以移动到[i-d,i+d]);③藏床底下(这样不会被计入人数)。

  若查寝时该寝室人数不为b则记录下来,假设2个老师的记录数分别为num1,num2,求max(num1,num2)的最小值。


思路:

  首先使用一个数组来记录前项和,并且求出中间位置,所有在中间位置左边部分的人都只在左边部分行动,右边的只在右边行动。

  所有人行动满足:①人多了,多出的人全向中间走;②人少了,如果所有能来的人都来了还不够,那就不来并且这个寝室的人也离开这个寝室向中间走。

  以左边为例,右边的对称过来思路一样。

  第1个寝室需要b人,那么可以在1~1+d这些寝室里凑人,即只要1+d的前项和比b大就可以满足。

  再看第2个寝室,如果之前第1个寝室没被记录,那么第1个寝室加上第2个寝室就需要2b个人才会不被记录,那这里需要2+2d的前项和比2*b大即可;如果第1个寝室被记录了,那么按照我们上面说的人不够就全跑,那第1个寝室加上第2个寝室就只需要b个人。

  这里为什么是2d呢。。因为在2+2d的人在第一轮检查的时候可以先移到2+d,在第二轮的时候就可以来到2这里。

  这样推下去的话就是在第i个寝室(左边部分),只要i+i*d的前项和比i-ans_i*b大就行(这里ans_i指的是左边部分已经被记录下来的寝室数),这个寝室就不会被记录。

  然后要注意的是要开long long,不然i+i*d会爆int。。被坑了好久才发现。。


AC代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cstdlib>
#include<utility>
#include<algorithm>
#include<utility>
#include<queue>
#include<vector>
#include<set>
#include<stack>
#include<cmath>
#include<map>
#define P pair<int,int>
#define ll long long
#define INF 100000000
#define M 1e9+7
#define MAX 500010
#define lson id*2,l,mid
#define rson id*2+1,mid+1,r
using namespace std;

ll n, d, b, ans_l, ans_r;
ll sum[100010];

int main()
{
	cin >> n >> d >> b;
	for (int i = 1; i <= n; i++)
		cin >> sum[i];
	for (int i = 2; i <= n; i++)
		sum[i] += sum[i - 1];

	ans_l = 0; ans_r = 0;
	ll l = 1, r = n;

	ll mid = lower_bound(sum + 1, sum + n + 1, sum[n] / 2) - sum;
	ll mid_l, mid_r;
	if (sum[mid] * 2 == sum[n]) {
		mid_l = mid;
		mid_r = mid + 1;
	}
	else {
		mid_l = mid;
		mid_r = mid;
	}

	while (l < r) {
		if (l + l*d < mid_l) {
			if (l + l*d >= 0 && l + l*d < n)
				if (sum[l + l*d] < (l - ans_l)*b)
					ans_l++;
		}

		if (r - l*d > mid_r) {
			if (r - l*d - 1 >= 0 && r - l*d - 1 < n)
				if (sum[n] - sum[r - l*d - 1] < (l - ans_r)*b)
					ans_r++;
		}
		l++; r--;
	}

	if (l == r) {
		if (l + l*d < mid_l) {
			if (l + l*d >= 0 && l + l*d < n)
				if (sum[l + l*d] < (l - ans_l)*b)
					ans_l++;
		}
	}

	cout << max(ans_l, ans_r) << endl;

	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40993793/article/details/80145189