其他分享
首页 > 其他分享> > CF1172F Nauuo and Bug 题解

CF1172F Nauuo and Bug 题解

作者:互联网

首先将问题转化为执行 sum(A,l,r,p) 后减去了多少次 \(p\)。

注意到若 \(x>y\),则 \(result\) 的初值为 \(x\) 时执行 sum(A,l,r,p) 中减去 \(p\) 的次数不少于 \(result\) 的初值为 \(y\) 时执行 sum(A,l,r,p) 中减去 \(p\) 的次数,故考虑建线段树并对区间 \([l,r]\) 维护 \(c_x\) 表示执行 sum(A,l,r,p) 后恰好减少了 \(x\) 次 \(p\),\(result\) 的最小值。

考虑如何 pushup,一种想法是枚举左儿子减去了 \(x\) 次 \(p\),右儿子减去了 \(y\) 次 \(p\) 进行合并,即若 \(c_{lson,x+1}-1+sum_{lson}-xp\ge c_{rson,y}\),则 \(c_{k,x+y}\) 对 \(\max(c_{lson,x},c_{rson,y}-sum_{lson}+xp)\) 取 \(\min\)。

考虑如何优化,注意到 \(c\) 是随下标增加而不降的,故 \(c_{lson,x+1}\ge c_{lson,x}\),又因为 \(c_{lson,x+1}\ge c_{rson,y}-sum_{lson}+xp\),所以 \(c_{lson,x+1}\ge\max(c_{lson,x},c_{rson,y}-sum_{lson}+xp)\),因而 \(\max(c_{lson,x+1},c_{rson,y-1}-sum_{lson}+(x+1)p)\ge\max(c_{lson,x},c_{rson,y}-sum_{lson}+xp)\)。因此对于每个 \(c_{k,x+y}\) 只需在 \(x\) 最小时更新即可。

我们下面证明上述不等式的左侧也是随下标增加而不降的,即证 \(c_{x+1}-c_{x}\ge p\)。

记 \(b_i\) 表示 \(result\) 的初值为 \(c_x\),对于序列 \(a_{1,..,n}\) 执行 sum(a,1,n,p) 时,第 \(9\) 行的 for 执行完第 \(i\) 次后 result 的值。记 \(d_i\) 表示 \(result\) 的初值为 \(c_x+p-1\),对于序列 \(a_{1,..,n}\) 执行 sum(a,1,n,p) 时,第 \(9\) 行的 for 执行完第 \(i\) 次后 result 的值。原命题等价于证明 \(b\) 中减去 \(p\) 的次数等于 \(c\) 中减去 \(p\) 的次数。

称一个位置是好的,当且仅当 \(result\) 在该位置上减去了 \(p\),可以发现 \(b\) 中至少有一个好的位置的值为 \(0\),否则将 \(c_x\) 减 \(1\) 后减去 \(p\) 的次数仍然是 \(x\) 次,与 \(c_x\) 的定义不符。

找到第一个位置使得该位置在 \(b\) 中不是好的且在 \(d\) 中是好的,在此之前 \(d\) 中数都比 \(b\) 中对应位置的数大 \(p-1\),接下来的一段 \(d\) 中数都比 \(b\) 中对应位置的数小 \(1\),于是可以找到该位置后的第一个位置使得该位置在 \(b\) 中是好的且在 \(d\) 中不是好的,接下来的一段 \(d\) 中数又都比 \(b\) 中对应位置的数大 \(p-1\)……

于是我们发现,\(d\) 中的数要么比 \(b\) 中对应位置的数大 \(p-1\),要么小 \(1\)。更进一步,设最后一个好的 \(0\) 的位置是 \(t\),则 \(d_{t-1}=b_{t-1}+p-1\) 或 \(d_{t-1}=b_{t-1}-1\),由于最后一个好的 \(0\) 在 \(b\) 中是由 \(p\) 减 \(p\) 得来的,故 \(b_{t-1}+a_t=p\),故 \(d_{t-1}+a_t=p-1\) 或 \(d_{t-1}+a_t=2p-1\),而这两种情况都能推出 \(d_t=p-1\),也就是说在 \(t\) 及之前 \(b\) 和 \(d\) 中的数减去 \(p\) 的次数是一样的。

将 \(c_x\) 减 \(1\) 后类似之前可推出新的由 \(result\) 组成的序列 \(b'\) 满足 \(\forall 1\le i\le n\),有 \(b'_i=b_i-1\) 或 \(b'_i=b_i+p-1\), 由 \(b_{t-1}+a_t=p\) 可得 \(b'_{t-1}+a_t=p-1\) 或 \(b'_{t-1}+a_t=2p-1\),而这两种情况也都能推出 \(b'_t=p-1\)。

由 \(c_x\) 的定义知 \(b'\) 中的数减去 \(p\) 的次数比 \(d\) 中的数减去 \(p\) 的次数少 \(1\),而我们又知道 \(b'\) 中的数在 \(t\) 及之前减去 \(p\) 的次数比 \(d\) 中的数在 \(t\) 及之前减去 \(p\) 的次数少 \(1\),故 \(b'\) 和 \(b\) 在 \(t\) 之后减去 \(p\) 的次数相等。又由于 \(b'\) 和 \(d\) 在 \(t\) 之后减去 \(p\) 的次数也相等,故 \(b\) 和 \(d\) 在 \(t\) 之后减去 \(p\) 的次数也相等。

因此,\(b\) 和 \(d\) 中的数减去 \(p\) 的次数是一样的,原命题得证。

由上述结论可知 pushup 更新 \(c\) 可用双指针将复杂度降低至 \(O(r-l+1)\),之后查询在线段树上的 \(\log n\) 个节点上二分出减去 \(p\) 的次数,即可以 \(O(\log^2n)\) 的时间复杂度回答单词询问。故总时间复杂度 \(O(n\log n+m\log^2n)\)。

Code

#include<bits/stdc++.h>
#define LL long long
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
int n,m;
LL p;
int a[1000002];
LL pre[1000002];
inline int lson(int x)
{
	return (x<<1);
}
inline int rson(int x)
{
	return ((x<<1)|1);
}
struct SegTree
{
	vector<LL> c[4000002];
	inline void build(int k,int l,int r)
	{
		if(l==r)return (void)(c[k].push_back(-inf),c[k].push_back(p-a[l]));
		int mid=((l+r)>>1),ls=lson(k),rs=rson(k);
		build(ls,l,mid),build(rs,mid+1,r);
		for(int i=0;i+1<c[ls].size()+c[rs].size();++i)c[k].push_back(i? inf:-inf);
		for(int i=0,j=0;i<c[ls].size();--j,++i)for(;j<c[rs].size() && (i+1==c[ls].size() || c[ls][i+1]-1+pre[mid]-pre[l-1]-p*i>=c[rs][j]);++j)c[k][i+j]=min(c[k][i+j],max(c[ls][i],c[rs][j]-pre[mid]+pre[l-1]+p*i));
	}
	inline int query(int k,int l,int r,int l1,int r1,LL d)
	{
		if(l>=l1 && r<=r1)
		{
			int L=0,R=c[k].size()-1,Mid;
			for(;L<=R;)
			{
				Mid=((L+R)>>1);
				if(c[k][Mid]<=d)L=Mid+1;
				else R=Mid-1;
			}
			return R;
		}
		int mid=((l+r)>>1),ls=lson(k),rs=rson(k),res;
		if(r1<=mid)return query(ls,l,mid,l1,r1,d);
		if(l1>mid)return query(rs,mid+1,r,l1,r1,d);
		return res=query(ls,l,mid,l1,mid,d),res+query(rs,mid+1,r,mid+1,r1,d+pre[mid]-pre[l1-1]-p*res);
	}
}S;
int main()
{
	scanf("%d%d%lld",&n,&m,&p);
	for(int i=1;i<=n;++i)scanf("%d",&a[i]),pre[i]=pre[i-1]+a[i];
	S.build(1,1,n);
	for(int x,y;m--;)scanf("%d%d",&x,&y),printf("%lld\n",pre[y]-pre[x-1]-p*S.query(1,1,n,x,y,0));
	return 0;
}

标签:次数,int,题解,sum,mid,Nauuo,lson,减去,Bug
来源: https://www.cnblogs.com/18Michael/p/16475832.html