令$a_{i}$和$b_{i}$分别为$A_{i}$和$B_{i}$减少的值,考虑判定$\{a_{i}\},\{b_{i}\}$能否被得到

结论:$\{a_{i}\},\{b_{i}\}$能否被得到当且仅当满足以下条件——

1.$0\le a_{i}\le A_{i}$,$0\le 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}$,注意到$0\le 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}$(其中$2\le k\le n-1$),同样可以忽略$0\le a_{k}\le A_{k}$的条件,因此操作$(i,j)$(其中$i<k<j$)不妨改为操作$(i,k)$和$(k,j)$,这样只让$A_{k}$额外减小2(仍合法)且操作数增加

换言之,不存在这样的操作,即不妨变为$[1,k]$和$[k,n]$这两个子问题

重复此过程,考虑最终的子问题,即有$\forall 2\le i\le 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 1\le j<i,a_{j}=A_{j}$,求出此时$b_{i}$可行的范围

若已经确定$b_{i-1}$,则$b_{i}$的范围为$\{x\mid x\in [\abs{A_{i}-b_{i-1}},\min(A_{i}+b_{i-1},B_{i})]$且$x\equiv a_{i}+b_{i-1}(mod\ 2)\}$,那么即要将$b_{i-1}$的范围内所有值代入并求并

归纳最终的形式为$\{x\mid x\in [L,B_{i}]$且$x\equiv 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\ne i,a_{j}=A_{j}$,按之前的方式求出$B_{i-1}$和$B_{i}$的区间即可

时间复杂度为$o(n\log 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\n",ans);
68 return 0;
69 }

[atAGC054F]Decrement的更多相关文章

  1. Interlocked.Increment 方法 和Interlocked.Decrement 方法作用

    Interlocked.Increment 方法:让++成为原子操作:Interlocked.Decrement 方法让--成为原子操作.什么叫原子操作呢.就是不会被别人打断,因为C#中的一个语句,编 ...

  2. STL——increment/decrement/dereference操作符

    increment/dereference操作符在迭代器的实现上占有非常重要的地位,因为任何一个迭代器都必须实现出前进(increment,operator++)和取值(dereference,ope ...

  3. 只有 assignment、call、increment、decrement 和 new 对象表达式可用作语句

    错误信息:只有 assignment.call.increment.decrement 和 new 对象表达式可用作语句: 分析:发生这种情况一般是在赋值时把“=”写成了“==”,例如:textBox ...

  4. increment/decrement/dereference

    #include <vector> #include <deque> #include <algorithm> #include <iostream> ...

  5. C#原子操作(Interlocked.Decrement和Interlocked.Increment)

    一.概念 在多线程环境中,不会被线程调度机制打断的操作:这种操作一旦开始,就一直运行到结束,中间不会有任何 context switch (切换到另一个线程). 二.类 System.Threadin ...

  6. ITEM M6 自增(INCREMENT)、自减(DECREMENT)操作符前缀形式与后缀形式的区别

    前缀自增 UPInt & UPint::operator++() { *this+=1; return *this; } 后缀自增 const UPInt & UPint::opera ...

  7. 【M6】区别increment/decrement操作符的前置(prefix)和后置(postfix)形式

    1.考虑++(--的情况是一样的),前置是累加然后取出,后置是取出然后累加. 2.重载方法根据形参表的不同区分,问题来了,前置和后置形式都没有形参,因此没法区分.怎么办? 对于后置增加一个形参int, ...

  8. increment/decrement/dereference操作符

    标题以上分别对于++/--/* #include <iostream> #include <cstddef> using namespace std; class INT { ...

  9. [atARC086F]Shift and Decrement

    将$A$操作看作直接除以2(保留小数),最终再将$a_{i}$取整 记$k$表示$A$操作的次数,$p_{i}$表示第$i$次$A$和第$i+1$次$A$之间$B$操作的次数(特别的,$p_{0}$为 ...

随机推荐

  1. 全套Java教程_Java基础入门教程,零基础小白自学Java必备教程 #011 # 第十一单元 String&ArrayList #

    一.本单元知识点概述 (Ⅰ)知识点概述 二.本单元教学目标 (Ⅰ)重点知识目标 1.ArrayList集合的常用方法2.ArrayList存储数据和遍历数据3.String类的构造方法4.String ...

  2. 极简SpringBoot指南-Chapter04-基于SpringBoot的书籍管理Web服务

    仓库地址 w4ngzhen/springboot-simple-guide: This is a project that guides SpringBoot users to get started ...

  3. Java入门基础,必读!Java单行、多行和文档注释!

    在编写Java的过程中,我们需要对一些程序进行注释.除了方便自己阅读之外,我们还需要为他人更好地理解我们的程序.因此,我们需要对一些程序进行注释,这些注释可以是编程思想,也可以是程序的作用,可以说是J ...

  4. Java秘诀!零基础怎样快速学习Java?

    对于零基础想学Java的朋友,其实一开始最应该做的就是定好学习目标和端正学习态度,切记不要三天打鱼两天晒网! 首先你是零基础,现在急需把Java学好,在保证学习质量的同时,用最短的时间学好Java应该 ...

  5. 微信小程序中路由跳转

    一.是什么 微信小程序拥有web网页和Application共同的特征,我们的页面都不是孤立存在的,而是通过和其他页面进行交互,来共同完成系统的功能 在微信小程序中,每个页面可以看成是一个pageMo ...

  6. ThreadLocalRandom类原理分析

    1.Random类及其局限性 public int nextInt(int bound) { if (bound <= 0) throw new IllegalArgumentException ...

  7. 分享一份软件测试项目实战(web+app+h5+小程序)

    大家好,我是谭叔. 本次,谭叔再度出马,给大家找了一个非常适合练手的软件测试项目,此项目涵盖web端.app端.h5端.小程序端,可以说非常之全面. 缘起 在这之前,谭叔已经推出了九套实战教程. 但是 ...

  8. UltraSoft - Alpha - Scrum Meeting 5

    Date: Apr q9th, 2020. Scrum 情况汇报 进度情况 组员 负责 昨日进度 后两日任务 CookieLau PM 统筹个人进度,协助推进进度 辅助前后端连接工作 刘zh 前端 完 ...

  9. C++ Boost signal2信号/插槽

    #include "stdafx.h" #include "boost/signals2.hpp" #include "boost/bind.hpp& ...

  10. 第一个只出现一次字符的位置 牛客网 剑指Offer

    第一个只出现一次字符的位置  牛客网 剑指Offer 题目描述 在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 ...