题解 CF1795C Tea Tasting
分析
正面想每个人能喝多少有点困难,但是可以从另一个方面想一杯茶能给多少人喝就做出来了。
不难理解,固定 $l$,$l$ 到 $r$ 的人喝的总量随着 $r$ 的增大而增大。
于是我们可以二分一杯茶可以提供给多少人喝,剩下的加到后面第一个没喝到的人头上。
要用前缀和和差分优化时间复杂度。
总体复杂度 $O(n\log{n})$,详情见代码注释。
代码
#include<iostream>
#define int long long
using namespace std;
int a[500005],s[500005],n,T,d[500005],f[500005],ans[500005];
signed main()
{
scanf("%lld",&T);
while(T--)
{
scanf("%lld",&n);
for(int i=1;i<=n;i++)scanf("%lld",&a[i]),f[i]=ans[i]=0;
for(int i=1;i<=n;i++)scanf("%lld",&s[i]);
for(int i=1;i<=n;i++)d[i]=d[i-1]+s[i];//前缀和优化
for(int i=1;i<=n;i++)
{
int l=i,r=n,mid,cnt=-1;//二分主体
while(l<=r)
{
mid=(l+r)>>1;
if(d[mid]-d[i-1]<=a[i])
{
l=mid+1;
cnt=mid;
}
else r=mid-1;
}
if(cnt!=-1)//记得特判一个人也不够
{
f[i]++;
f[cnt+1]--;//差分优化
ans[cnt+1]+=a[i]-d[cnt]+d[i-1];
}
else ans[i]+=a[i];
}
for(int i=1;i<=n;i++)f[i]+=f[i-1];//输出
for(int i=1;i<=n;i++)printf("%lld ",ans[i]+f[i]*s[i]);
puts("");
}
}