zoukankan      html  css  js  c++  java
  • 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;
    }
    
    
  • 相关阅读:
    HDU 5640 King's Cake
    HDU 5615 Jam's math problem
    HDU 5610 Baby Ming and Weight lifting
    WHU1604 Play Apple 简单博弈
    HDU 1551 Cable master 二分
    CodeForces659C Tanya and Toys map
    Codeforces 960E 树dp
    gym 101485E 二分匹配
    Codeforces 961E 树状数组,思维
    Codeforces Round #473 (Div. 2) D 数学,贪心 F 线性基,模板
  • 原文地址:https://www.cnblogs.com/jz-597/p/14966859.html
Copyright © 2011-2022 走看看