用二分+前缀和样例都过,评测全错,求大佬帮助
  • 板块P9519 pay
  • 楼主duanzx
  • 当前回复0
  • 已保存回复0
  • 发布时间2023/8/16 19:48
  • 上次更新2023/11/3 03:18:09
查看原帖
用二分+前缀和样例都过,评测全错,求大佬帮助
1008172
duanzx楼主2023/8/16 19:48
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define vct vector
#define que queue
#define stk stack
#define sct struct
#define str string
#define N 1145141
#define k mid
int n, m;
int a[N];
int b[N];
ll mid;
bool solve() {
//	cout << '\n' << mid << " \n";
	vct <ll> p1(N);
	vct <ll> p2(N);
	//差分 
	for (int i = 1; i <= m; i ++) {
//		cout << "*";
		if (b[i] - k + 1 >= 1 && b[i] - k + 1 <= n) p1[b[i] - k + 1] ++;
		else p1[1] ++;
		
		if (b[i] + 1 <= n) p1[b[i] + 1] --;
		
		if (b[i] + k - 1 >= 1 && b[i] + k - 1 <= n) {
			p2[b[i] + k - 1] ++;	
//			cout << b[i] - k + 1 << '\n';
		}
		else {
				p2[n] ++;
			}		
		p2[b[i]] --;
	}
//	for (int i = 1; i <= n; i ++) {
//		cout << p1[i] << ' ';
//	}
//	cout << '\n';
//	for (int i = 1; i <= n; i ++) {
//		cout << p2[i] << ' ';
//	}
//	cout << '\n';
	
	//两次前缀和
	for (int i = 1; i <= n; i ++) {
		p1[i] = p1[i - 1] + p1[i];
	} 
	for (int i = 1; i <= n; i ++) {
		p1[i] = p1[i - 1] + p1[i];
	}
//	for (int i = 1; i <= n; i ++) {
//		cout << p1[i] << ' ';
//	}
//	cout << '\n';
	//两次后缀和
	for (int i = n; i ; i --) {
		p2[i] = p2[i + 1] + p2[i];
	} 
	for (int i = n; i ; i --) {
		p2[i] = p2[i + 1] + p2[i];
	}
//	for (int i = 1; i <= n; i ++) {
//		cout << p2[i] << ' ';
//	}
//	cout << '\n';
	//相加、判断 
	for (int i = 1; i <= n; i ++) {
		p1[i] += p2[i];
//		cout << p1[i] << ' ';
		if (p1[i] < a[i]) {
//			cout << '\n';
			return 0;
		}
	}
	return 1;
}

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> n >> m;
	for (int i = 1; i <= n; i ++) {
		cin >> a[i];
	}
	for (int i = 1; i <= m; i ++) {
		cin >> b[i];
	}
	ll l = 1;
	ll r = 1000000000;
	while (l <= r) {
		mid = (l + r) / 2;
		if (solve()){
			if (l == r) {
				cout << mid;
				return 0;
			}
			r = mid;
		} else {
			l = mid + 1;
		}
	}
	/*
	5  2  6  3  1
	
	1        1
	
	二分答案
	
	l = 1;
	r = 10 ^ 10;
	如果m满足要求,那么r = m(如果只有一个元素,那么直接输出m) 
	如果m不满足要求,那么l = m + 1 
	--------------------------------
	差分+前缀和+后缀和
	
	第i次发工资发给b[i]
前缀d1[]:  在b[i] - k + 1的位置++,
		  在b[i] + 1的位置--
		  这样两次前缀和后得到逐渐升序的序列
		 
			
后缀d2[]: 在 b[i] + k - 1的位置++
			在b[i]的位置--
			(由于b[i]只能加一次)
			这样两次后缀和后得到逐渐降序的序列
	最后,将p1和p2每个元素相加,即
	得到每个员工的快乐值 
	改变:O(m) 求前缀和/相加/判断是否可行 :O(n) 
	总时间复杂度:O(logx(m + n)) 
	*/
}
2023/8/16 19:48
加载中...