AGC054F

有两个长度分别为(n)(n-1)的数组(A,B)

每次可以选择(l<r),操作(A_l,A_r)(B_l,B_{l+1},dots,B_{r-1}),将其减一。要求操作之后不能出现负数。

问在操作次数最多的前提下,操作之后不同的数组(a)的方案数。

(nle 2*10^5)


假设(A_i,B_i)最终各减了(a_i,b_i)。考虑(a_i,b_i)能够减完的充要条件:

(b_0=b_n=0)

  1. (2|(a_i+b_{i-1}+b_i))
  2. (max(a_i,b_{i-1},b_i)le frac{a_i+b_{i-1}+b_i}{2})

证明:

必要性:以(a_i,b_{i-1},b_i)的视角考虑,每次与其有关的操作一定是选择其中两个减一。

充分性:归纳。假如操作了(l,r),必须要满足:(forall iin(l,r),a_i<b_{i-1}+b_i)(b_{l-1}<a_l+b_l,b_r<a_r+b_{r-1})。如果将(a_i=b_{i-1}+b_i)的点提取出来,任取相邻两个操作,就可以满足。((1)(n)一定满足,所以至少两个)

先调整(B_i)(A_i)。如果(B_{i-1}>A_i+B_i),则将其调整为(B_{i-1})(B_i)类似。搞完(B)之后,如果出现(A_ige B_{i-1}+B_i),可以将问题以(i)为分界分开,对于左边假装(A_i=B_{i-1}),对于右边假装(A_i=B_{i})

然后要最大化(sum a_i)。对于一个子问题,数下(t_i=(A_i+B_{i-1}+B_i)mod 2=1)的个数(c),如果(2|c),把相邻的(t_i=1)(i)两两配对,每对之间的(B)减一,此时(sum A_i)取到(sum A_i);否则至多取到(sum A_i-1),如果钦定(a_1=A_1-1),用类似的方法也可以达到这个界。

算方案:如果(2|c)则唯一;否则要对每个(i)判断一下能否取(a_i=A_i-1),这个东西做个前缀和后缀的DP,合并起来即可。具体:设(f_{i})表示(a_1,dots,a_i)(A_1,dots,A_i),此时(b_i)可行的取值(区间+奇偶性),另一边类似。

题解说时间(O(n)),然而我不知道前面调整(B)的那部分怎么(O(n))做,我是直接跑最短路的……


using namespace std;
#include <bits/stdc++.h>
const int N=200005,mo=998244353;
typedef long long ll;
#define fi first
#define se second
#define mp make_pair
int n;
int a[N],b[N];
priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > q;
void init(){
	for (int i=0;i<=n;++i)
		q.push(mp(b[i],i));
	while (!q.empty()){
		int x=q.top().se,s=q.top().fi;
		q.pop();
		if (s>b[x]) continue;
		if (x>0 && a[x]+b[x]<b[x-1]){
			b[x-1]=a[x]+b[x];
			q.push(mp(b[x-1],x-1));
		}
		if (x<n && a[x+1]+b[x]<b[x+1]){
			b[x+1]=a[x+1]+b[x];
			q.push(mp(b[x+1],x+1));
		}
	}
}
struct status{int l,r,c;} f[N],g[N];
status merge(status x,status y){
	status z;
	z.c=x.c^y.c;
	z.r=x.r+y.r;
	if (max(x.l,y.l)<=min(x.r,y.r))
		z.l=z.c;
	else
		z.l=min(abs(x.l-y.r),abs(x.r-y.l));
	return z;
}
ll work(int l,int r){
	if (l==r) return 1;
	int c=0;
	c^=a[l]+b[l]&1;
	c^=a[r]+b[r-1]&1;
	for (int i=l+1;i<r;++i)
		c^=a[i]+b[i-1]+b[i]&1;
	if (c^1)
		return 1;
	f[l-1]={0,0,0};
	for (int i=l;i<r;++i){
		f[i]=merge(f[i-1],(status){a[i],a[i],a[i]&1});
		f[i].r=min(f[i].r,b[i]);
		if (f[i].r&1^f[i].c)
			f[i].r--;
	}
	g[r+1]={0,0,0};
	for (int i=r;i>l;--i){
		g[i]=merge(g[i+1],(status){a[i],a[i],a[i]&1});
		g[i].r=min(g[i].r,b[i-1]);
		if (g[i].r&1^g[i].c)
			g[i].r--;
	}
	/*
	for (int i=l;i<=r;++i){
		printf("(%d,%d,%d) (%d,%d,%d)
",f[i].l,f[i].r,f[i].c,g[i].l,g[i].r,g[i].c);
	}*/
	ll cnt=0;
	for (int i=l;i<=r;++i){
		status t=merge(f[i-1],g[i+1]);
		if (t.c==(a[i]-1&1) && (t.l<=a[i]-1 && a[i]-1<=t.r)){
			//printf("%d
",i);
			cnt++;
		}
	}
	return cnt;
}
int main(){
	freopen("in.txt","r",stdin);
	scanf("%d",&n);
	for (int i=1;i<=n;++i)
		scanf("%d",&a[i]);
	for (int i=1;i<n;++i)
		scanf("%d",&b[i]);
	init();
	ll ans=1;
	int lst=1;
	for (int i=1;i<=n;++i){
		if (a[i]>=b[i-1]+b[i]){
			a[i]=b[i-1];
			ans=ans*work(lst,i)%mo;
			lst=i;
			a[i]=b[i];
		}
	}
	ans=ans*work(lst,n)%mo;
	printf("%lld
",ans);
	return 0;
}

原文地址:https://www.cnblogs.com/jz-597/p/14966859.html