• [cf1434E]A Convex Game


    暴力求SG,结论:每一个序列的SG上限为$sqrt{2max a_{i}}+1$

    证明:将SG的转移看作一张DAG,归纳每一个点的SG值不超过其开始的最长路,显然成立

    那么本题中最长路即在$a_{i}$中最多能选多少次,假设选择的权值依次为$v_{1},v_{2},...,v_{m}$,则$v_{i+1}-v_{i}ge i$,累加即$v_{m}-v_{1}ge frac{m(m-1)}{2}$,放缩得$(m-1)^{2}<2v_{m}$,$m$也即SG的上限为$sqrt{2max a_{i}}+1$

    考虑dp,令$f_{i,j}$表示最后两次分别选了$a_{i}$和$a_{j}$的SG值,转移为$f_{i,j}=mex({f_{k,i}|a_{k}-a_{i}>a_{i}-a_{j}})$,利用$k$的单调性,倒序枚举$j$,可以做到$o(n^{2})$,最终答案即为$mex({f_{i,0}|1le ile n})$

    令$g_{i,j}=min_{f_{i,k}>j}k$,根据上面的结论,$g$的总数量为$o(nsqrt{n})$,考虑直接转移$g$

    根据单调性,有$g_{i,j}ge g_{i,j-1}$,这也就保证了$f_{i,g_{i,j}}$后面的集合包含了$[1,j)$,同时$j$也需要出现,因此即要求$exists k,a_{g_{i,j}}>2a_{i}-a_{k}且f_{k,i}=j$,后者又等价于$g_{k,j-1}le i<g_{k,j}$,贪心求出满足后者的$k$中最大值即可

    考虑先枚举$j$,维护线段树,每一次先查询$i$上的值并判断,再令区间$[g_{i,j-1},g_{i,j})$的值对$i$取max,时间复杂度为$o(nsqrt{n}log_{2}n)$,略微卡常

    进一步优化,由于插入的区间单调递增,因此可以看作对未被修改的部分修改,维护两个并查集,分别表示:1.上一个未被覆盖的点;2.同一种类型的上一个点,时间复杂度为$o(nsqrt{n}alpha(n))$

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 100005
     4 #define L (k<<1)
     5 #define R (L+1)
     6 #define mid (l+r>>1)
     7 int t,n,ans,a[N],f[2][N],fa[N],pre[N],v[N];
     8 int find(int k){
     9     if (fa[k]==k)return k;
    10     return fa[k]=find(fa[k]);
    11 }
    12 int get_pre(int k){
    13     if (k==pre[k])return k;
    14     return pre[k]=get_pre(pre[k]);
    15 }
    16 void update(int l,int r,int x){
    17     r=get_pre(r);
    18     if (v[r])r--;
    19     if (l>r)return;
    20     while (1){
    21         int nex=get_pre(r-1);
    22         if (v[nex])nex--;
    23         if (nex<l){
    24             v[r]=x;
    25             return;
    26         }
    27         fa[r]=nex;
    28         r=nex;
    29     }
    30 }
    31 void merge(int l,int r){
    32     if ((r<=n)&&(pre[r+1]==r+1)&&(v[r+1]))pre[r+1]=r;
    33     r=get_pre(r);
    34     while (l<r){
    35         pre[r]=r-1;
    36         r=get_pre(r-1);
    37     }
    38     if ((l==r)&&(l>1)&&(v[get_pre(l-1)]))pre[r]=r-1;
    39 }
    40 int query(int k){
    41     return v[find(k)];
    42 }
    43 int main(){
    44     scanf("%d",&t);
    45     while (t--){
    46         scanf("%d",&n);
    47         for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    48         int s=0,p=0,flag=0;
    49         for(int i=1;i<=n;i++)f[p][i]=1;
    50         while (!flag){
    51             flag=1;
    52             s++;
    53             p^=1;
    54             for(int i=1;i<=n;i++){
    55                 fa[i]=pre[i]=i;
    56                 v[i]=0;
    57             }
    58             for(int i=n;i;i--){
    59                 int k=query(i);
    60                 if(!k)f[p][i]=n+1;
    61                 else f[p][i]=upper_bound(a+1,a+n+1,2*a[i]-a[k])-a;
    62                 if (f[p^1][i]>=f[p][i])f[p][i]=f[p^1][i];
    63                 else{
    64                     update(f[p^1][i],f[p][i]-1,i);
    65                     merge(f[p^1][i],f[p][i]-1);
    66                 }
    67                 if (f[p][i]<=n)flag=0;
    68             }
    69         }
    70         ans^=s;
    71     }
    72     if (ans)printf("YES");
    73     else printf("NO");
    74 } 
    View Code
  • 相关阅读:
    C语言I博客作业05
    C语言I博客作业04
    C语言II博客作业01
    学期总结
    第一周作业
    C语言I博客作业08
    C语言I博客作业07
    C语言I博客作业06
    C语言I博客作业05
    C语言I博客作业04
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/13900930.html
Copyright © 2020-2023  润新知