• 【Codeforces】 CF1870E Another MEX Problem


    题目链接

    CF方向
    Luogu方向

    题目解法

    解法1
    考虑优化 d p dp dp 转移次数,即只转移有用的区间
    不难发现, m e x ( l , r ) = m e x ( l + 1 , r ) mex(l,r)=mex(l+1,r) mex(l,r)=mex(l+1,r) m e x ( l , r ) = m e x ( l , r − 1 ) mex(l,r)=mex(l,r-1) mex(l,r)=mex(l,r1),那么区间 [ l , r ] [l,r] [l,r] 就没用
    考虑证明剩下有用的区间个数是 O ( n ) O(n) O(n)
    [ l , r ] [l,r] [l,r] 是有用的,我们不妨令 a l > a r a_l>a_r al>ar
    如果有 R > r R>r R>r 且满足 [ l , R ] [l,R] [l,R] 是有用的,且 a l > a R a_l>a_R al>aR
    根据上面的定义, m e x ( l , r ) > a l mex(l,r)>a_l mex(l,r)>al,不然可以踢掉 l l l,所以 a R < m e x ( l , r ) a_RaR<mex(l,r),那么 r r r 就没有加的必要
    所以对于 a l > a r a_l>a_r al>ar,有用的 r r r 只有一个
    对于 a l < a r a_lal<ar 同理, a l = a r a_l=a_r al=ar 随便删去 l , r l,r l,r 都比 [ l , r ] [l,r] [l,r]
    所以剩余的区间个数是 2 n 2n 2n
    直接 d p dp dp 即可

    #include 
    #define pb push_back
    using namespace std;
    const int N=5100;
    int mex[N][N],cnt[N],a[N];
    bool ok[N][N<<1];
    vector<int> trans[N];
    inline int read(){
        int FF=0,RR=1;
        char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
        for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
        return FF*RR;
    }
    void work(){
        int n=read();
        for(int i=1;i<=n;i++) a[i]=read();
        for(int i=1;i<=n;i++){
            int curmex=0;
            for(int j=i;j<=n;j++){
                cnt[a[j]]++;
                while(cnt[curmex]) curmex++;
                mex[i][j]=curmex;
            }
            for(int j=0;j<=n;j++) cnt[j]=0;
        }
        for(int i=1;i<=n;i++) for(int j=i;j<=n;j++) if(mex[i][j]!=mex[i+1][j]&&mex[i][j]!=mex[i][j-1]) trans[j].pb(i);
        ok[0][0]=1;
        for(int i=1;i<=n;i++){
            for(int j=0;j<=n<<1;j++) ok[i][j]=ok[i-1][j];
            for(int j:trans[i]) for(int k=0;k<=n<<1;k++) if(ok[j-1][k]) ok[i][k^mex[j][i]]=1;
        }
        for(int i=n<<1;;i--) if(ok[n][i]){ printf("%d\n",i);break;}
        for(int i=1;i<=n;i++) trans[i].clear();
    }
    int main(){
        int T=read();
        while(T--) work();
        fprintf(stderr,"%d ms\n",int(1e3*clock()/CLOCKS_PER_SEC));
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    解法2
    我们发现 m e x mex mex 的上界是 2 n 2n 2n
    所以我们考虑 g i g_i gi 表示异或 m e x mex mex 和为 i i i 最少需要的前缀长度
    显然 g i g_i gi 可用类似最短路的方式实现
    但这样会多一个 l o g log log,因为值域较小,开 n n n v e c t o r vector vector 存最优位置对应的异或 m e x mex mex 值即可

  • 相关阅读:
    合并请求格式太乱?工单内容各写各的?表单模板来帮你
    微信小程序设计之主体文件app-wxss/less
    python疫苗预约系统毕业设计开题报告
    redis宕机导致数据丢失的重大生产事故总结
    selenium-语法
    程序员的注释:编程艺术与沟通工具
    SpringBoot SpringBoot 开发实用篇 3 测试 3.3 测试类中启动web 环境
    leetcode 1004.最大连续1的个数 III 滑动窗口
    开发工具
    听,引擎的声音「GitHub 热点速览 v.22.33」
  • 原文地址:https://blog.csdn.net/djx2021/article/details/134299644