[P9519] Pay

Solution

由于 \(k\) 的大小具有单调性,考虑二分,但检查当前 \(k\) 是否合法是个问题。

考虑第 \(b_i\) 个员工对于周围的人及自己的欢乐值的贡献。( 形似 \(a(b)\) 形式表示对第 \(b\) 个员工的快乐值贡献为 \(a\)

\[\begin{matrix} \underbrace{1,2,\cdots,k(b_i)}\\k \end{matrix} \;\; \begin{matrix} \underbrace{k-1,\cdots,1,0}\\k \end{matrix} \]

对于某个发工资的员工来说,暴力计算贡献 \(\mathcal O(n)\) 的,不可行。 考虑对序列做差分。

\[\begin{matrix} \underbrace{1,\cdots,1(b_i)}\\k \end{matrix} \;\; \begin{matrix} \underbrace{-1,\cdots,-1}\\k \end{matrix} \]

将这个序列记作 \(d_1\)

此时暴力还是 \(\mathcal O(n)\) 的,考虑继续对序列做差分。

\[1(\max(b_i-k+1,0)),-2(b_i+1),1(b_i+k+1) \]

将这个序列记作 \(d_2\)

在进行两次差分后,可以 \(O(1)\) 计算某个员工对于Ta及Ta周围的人贡献了。

但如果 \(b_i-k+1<0\) 会导致计算出错。此时 \(d_{1,0}\)\(1\)(只考虑某个 \(b_i\)),而我们希望它为 \(k-b_i\) ,因此我们要对 \(d_{1,0}\) 增加 \(k-b_i-1\) 的贡献。

P.S. 二分上界不为 \(\max(a_i)\) 而应是 \(\max(a_i)+n\)

总时间复杂度 \(\mathcal O((n+m)\log V)\)

Code

此处给出部分关键代码。

int n,m,a[N],b[N];
long long c[N];
bool check(int k) {
	for(int i=0;i<=n;i++) c[i]=0;
	for(int i=1;i<=m;i++) {
		++c[max(0,b[i]-k+1)];
		c[b[i]+1]-=2;
		if(b[i]+k+1<=n) ++c[b[i]+k+1];
	}
	for(int i=1;i<=n;i++) c[i]+=c[i-1];
	for(int i=1;i<=m;i++) if(k>b[i]) c[0]+=k-b[i]-1;
	for(int i=1;i<=n;i++) c[i]+=c[i-1];
	for(int i=1;i<=n;i++) if(c[i]<a[i]) return false;
	return true;
}
void Solve() {
    // mx 为 max(a[i])
	int l=0,r=mx+n,mid;
	while(l<r) {
		mid=l+r>>1;
		if(check(mid)) r=mid;
		else l=mid+1;
	}
	printf("%d\n",l);
}
posted @ 2023-08-12 19:54  ASnown  阅读(61)  评论(0)    收藏  举报