[atAGC054F]Decrement
令$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的更多相关文章
- Interlocked.Increment 方法 和Interlocked.Decrement 方法作用
Interlocked.Increment 方法:让++成为原子操作:Interlocked.Decrement 方法让--成为原子操作.什么叫原子操作呢.就是不会被别人打断,因为C#中的一个语句,编 ...
- STL——increment/decrement/dereference操作符
increment/dereference操作符在迭代器的实现上占有非常重要的地位,因为任何一个迭代器都必须实现出前进(increment,operator++)和取值(dereference,ope ...
- 只有 assignment、call、increment、decrement 和 new 对象表达式可用作语句
错误信息:只有 assignment.call.increment.decrement 和 new 对象表达式可用作语句: 分析:发生这种情况一般是在赋值时把“=”写成了“==”,例如:textBox ...
- increment/decrement/dereference
#include <vector> #include <deque> #include <algorithm> #include <iostream> ...
- C#原子操作(Interlocked.Decrement和Interlocked.Increment)
一.概念 在多线程环境中,不会被线程调度机制打断的操作:这种操作一旦开始,就一直运行到结束,中间不会有任何 context switch (切换到另一个线程). 二.类 System.Threadin ...
- ITEM M6 自增(INCREMENT)、自减(DECREMENT)操作符前缀形式与后缀形式的区别
前缀自增 UPInt & UPint::operator++() { *this+=1; return *this; } 后缀自增 const UPInt & UPint::opera ...
- 【M6】区别increment/decrement操作符的前置(prefix)和后置(postfix)形式
1.考虑++(--的情况是一样的),前置是累加然后取出,后置是取出然后累加. 2.重载方法根据形参表的不同区分,问题来了,前置和后置形式都没有形参,因此没法区分.怎么办? 对于后置增加一个形参int, ...
- increment/decrement/dereference操作符
标题以上分别对于++/--/* #include <iostream> #include <cstddef> using namespace std; class INT { ...
- [atARC086F]Shift and Decrement
将$A$操作看作直接除以2(保留小数),最终再将$a_{i}$取整 记$k$表示$A$操作的次数,$p_{i}$表示第$i$次$A$和第$i+1$次$A$之间$B$操作的次数(特别的,$p_{0}$为 ...
随机推荐
- 数字图像处理(一)之灰度转换和卷积python实现
使用Python实现数字图像处理中如下功能: 彩色图像转成灰度图像 实现图像的相关&卷积操作 实现图像的高斯核卷积 使用的库和python版本如下: imageio:2.9.0 用于读取磁盘中 ...
- ElasticSearch IK热词自动热更新原理与Golang实现
热更新概述 ik分词器本身可以从配置文件加载扩张词库,也可以从远程HTTP服务器加载. 从本地加载,则需要重启ES生效,影响比较大.所以,一般我们都会把词库放在远程服务器上.这里主要有2种方式: 借助 ...
- YouTube爬虫下载
最近在想用爬虫写youtube网站下载学习视频,找了好多资料也没有有个有用的. 真不容易找到几行代码,代码实现很简单,基于youtube_dl 来之不易,仅参考 from __future__ imp ...
- 开源协同OA办公平台教程:O2OA服务管理中,接口的调用权限
本文介绍O2OA服务管理中,接口的权限设定和调用方式. 适用版本:5.4及以上版本 创建接口 具有服务管理设计权限的用户(具有ServiceManager角色或Manager角色)打开" ...
- 激活NX窗口的按钮
原理:取得按钮名称以后,通过运行宏文件激活按钮 Imports System.IO Imports System.Runtime.InteropServices Imports NXOpen.Menu ...
- WinForm RichTextBox 常用操作
1.设置不自动选择字词 RichTextBox在选择文字的时候,如果没有关闭自动选择字词功能,我们有时候选择的时候会自动将光标前后的字或者词连接在一起进行选择. RichTextBox有属性AutoW ...
- nsq - 一条消息的生命周期(一)
经过前面几篇的学习,相信大家对nsq已经有了一个大概的了解,我在写这篇文章的时候也看了很多其他人写的教程,发现大家对于分析系统每个点写的很不错,但是都很少有整体串起来一起走一遍,所以,我打算分成2-3 ...
- 微信小程序实现tabs选项卡
选项卡在我们的日常开发中,使用的还是蛮多的,但是微信小程序中却没有直接提供选项卡组件,不过我们可以变通通过 scroll-view 和 swiper 组件来实现一个选项卡的功能. 需求: 实现一个选项 ...
- 热身训练4 Article
Article 在这个学期即将结束时,DRD开始写他的最后一篇文章. DRD使用著名的Macrohard的软件World来写他的文章. 不幸的是,这个软件相当不稳定,它总是崩溃. DRD需要在他的文章 ...
- Python中的括号()、[]、{}
长时间不用容易混淆,仅记! 在Python语言中最常见的括号有三种,分别是:小括号().中括号[].花括号{} . Python中的小括号(): 代表tuple元祖数据类型,元祖是一种不可变序列.大多 ...