[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);
}

浙公网安备 33010602011771号