zoukankan      html  css  js  c++  java
  • [atAGC054F]Decrement

    令$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 } 
    View Code
  • 相关阅读:
    前端开发—HTML
    初识 Django
    前端开发—BOM对象DOM文档对象操作
    前端开发—jQuery
    前端开发—Javascript
    前端开发—CSS 盒子、浮动、定位
    前端开发—CSS
    html模拟手机页面
    人类简史读书笔记
    正则表达式
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/15369908.html
Copyright © 2011-2022 走看看