令$a_{i}$和$b_{i}$分别为$A_{i}$和$B_{i}$减少的值,考虑判定${a_{i}},{b_{i}}$能否被得到
结论:${a_{i}},{b_{i}}$能否被得到当且仅当满足以下条件——
1.$0le a_{i}le A_{i}$,$0le b_{i}le B_{i}$
2.$a_{i}+b_{i-1}+b_{i}$为偶数(其中$b_{0}=b_{n}=0$)
3.$a_{i},b_{i-1},b_{i}$这三个数中不存在一个数大于另外两数之和
必要性——第1个条件由非负的限制显然,第2个和第3个条件均考虑$a_{i},b_{i-1},b_{i}$这三个数中,每一次对其中一个数+1,另外两数中必然恰有一个数+1,显然具有上述性质
充分性——归纳,并考虑最后一次操作,取第一个$a_{i}>0$的位置和其之后第一个$a_{j}=b_{j-1}+b_{j}$的位置即可(具体存在性和正确性可以自行分析)
对于$A_{i}+B_{i-1}<B_{i}$,注意到$0le b_{i}le B_{i}$即为第3个条件的必要条件,可以忽略此条件,因此不妨调整为$B_{i}=A_{i}+B_{i-1}$(类似地,也可以对$B_{i-1}$做此操作)
重复此过程(可以用类似dijkstra的贪心来做),即有$|B_{i}-B_{i-1}|le A_{i}$
此时,对于$A_{k}ge B_{k-1}+B_{k}$(其中$2le kle n-1$),同样可以忽略$0le a_{k}le A_{k}$的条件,因此操作$(i,j)$(其中$i<k<j$)不妨改为操作$(i,k)$和$(k,j)$,这样只让$A_{k}$额外减小2(仍合法)且操作数增加
换言之,不存在这样的操作,即不妨变为$[1,k]$和$[k,n]$这两个子问题
重复此过程,考虑最终的子问题,即有$forall 2le ile n-1,|B_{i}-B_{i-1}|le A_{i}<B_{i-1}+B_{i}$,且类似前面的,不妨再令$A_{1}=B_{1},A_{n}=B_{n-1}$
(注意这个过程的实现并不需要递归,直接从前往后枚举并划分即可)
另一方面,注意到操作次数即为$frac{sum_{i=1}^{n}a_{i}}{2}$,同时${a_{i}}$与最终的${A_{i}}$一一对应,因此从${a_{i}}$的角度来看,问题即求有多少组${a_{i}}$满足$frac{sum_{i=1}^{n}a_{i}}{2}$取到最大值且$exists {b_{i}}$满足结论中的条件
考虑从前往后依次填$b_{i}$,并要求$forall 1le j<i,a_{j}=A_{j}$,求出此时$b_{i}$可行的范围
若已经确定$b_{i-1}$,则$b_{i}$的范围为${xmid xin [abs{A_{i}-b_{i-1}},min(A_{i}+b_{i-1},B_{i})]$且$xequiv a_{i}+b_{i-1}(mod 2)}$,那么即要将$b_{i-1}$的范围内所有值代入并求并
归纳最终的形式为${xmid xin [L,B_{i}]$且$xequiv p(mod 2)}$且该集合非空(也即必然包含$B_{i}-1$或$B_{i}$),转移可以自行分类讨论得到(式子较为复杂),进而不难证明归纳
以此法构造,即$a_{1},a_{2},...,a_{n-1}$都可以取到$A_{i}$,且$a_{n}$可以取到$A_{n}-1$或$A_{n}$,显然$sum_{i=1}^{n}a_{i}equiv 0(mod 2)$,因此$a_{n}$的取值可以直接确定,进而不难发现$frac{sum_{i=1}^{n}a_{i}}{2}$已经取到上限
换言之,若$sum_{i=1}^{n}A_{i}$为偶数,则取到最大值仅有$a_{i}=A_{i}$时(方案数为1),否则即对每一个$i$判断是否可以令$a_{i}=A_{i}-1$且$forall j e i,a_{j}=A_{j}$,按之前的方式求出$B_{i-1}$和$B_{i}$的区间即可
时间复杂度为$o(nlog n)$(调整$B_{i-1}$和$B_{i}$),可以通过
(代码中转移的部分有点丑)

1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 200005 4 #define mod 998244353 5 #define ll long long 6 priority_queue<pair<int,int> >q; 7 int n,ans,a[N],b[N],vis[N],L[N],p[N]; 8 int get(int k,int p){ 9 if ((k&1)!=p)k--; 10 return k; 11 } 12 int calc(int x,int y){ 13 a[x]=b[x],a[y]=b[y-1]; 14 int s=0; 15 for(int i=x;i<=y;i++)s^=(a[i]&1); 16 if (!s)return 1; 17 L[x-1]=p[x-1]=0; 18 for(int i=x;i<=y;i++){ 19 p[i]=(p[i-1]^(a[i]&1)); 20 if (L[i-1]>=a[i])L[i]=L[i-1]-a[i]; 21 else L[i]=get(max(a[i]-get(b[i-1],p[i-1]),0)+1,p[i]); 22 } 23 int LL=0,pp=0,ans=0; 24 for(int i=y;i>=x;i--){ 25 int x=get(b[i-1],p[i-1]),y=get(b[i],pp); 26 if (a[i]-1<=x+y){ 27 if (abs(x-y)<=a[i]-1)ans++; 28 else{ 29 if (a[i]-1<=x+y-2){ 30 if ((x>y)&&(L[i-1]<=x-2))ans++; 31 if ((x<y)&&(LL<=y-2))ans++; 32 } 33 } 34 } 35 if (LL>=a[i])LL-=a[i]; 36 else LL=get(max(a[i]-get(b[i],pp),0)+1,(pp^(a[i]&1))); 37 pp^=(a[i]&1); 38 } 39 return ans; 40 } 41 int main(){ 42 scanf("%d",&n); 43 for(int i=1;i<=n;i++)scanf("%d",&a[i]); 44 for(int i=1;i<n;i++)scanf("%d",&b[i]); 45 for(int i=0;i<=n;i++)q.push(make_pair(-b[i],i)); 46 while (!q.empty()){ 47 int k=q.top().second; 48 q.pop(); 49 if (vis[k])continue; 50 vis[k]=0; 51 if ((k)&&(b[k-1]>a[k]+b[k])){ 52 b[k-1]=a[k]+b[k]; 53 q.push(make_pair(-b[k-1],k-1)); 54 } 55 if ((k<n)&&(b[k+1]>a[k+1]+b[k])){ 56 b[k+1]=a[k+1]+b[k]; 57 q.push(make_pair(-b[k+1],k+1)); 58 } 59 } 60 int lst=ans=1; 61 for(int i=2;i<=n;i++) 62 if (a[i]>=b[i-1]+b[i]){ 63 int x=b[i]; 64 b[i]=0,ans=(ll)ans*calc(lst,i)%mod; 65 lst=i,b[i-1]=0,b[i]=x; 66 } 67 printf("%d ",ans); 68 return 0; 69 }