zoukankan      html  css  js  c++  java
  • 【UR #13】Yist

    UOJ小清新题表

    题目摘要

    UOJ链接

    给出一个排列 (A) 以及它的一个非空子序列 (B),给出一个 (x) 并进行若干次操作,每一次操作需要在 (A) 中选择一个长度恰好为 (x) 的区间并删除它的最小值。如果在操作结束以后剩下的数组恰好是 (B),那么就可以得到 (x) 分,否则得到 (0) 分。

    (q) 组询问,所有的 (A) 序列都是一样的,但 (B) 序列不同。求每次询问能得到的最大得分。

    (B) 序列是一个 01 串,若该位置上为 (1) ,则表示 (A) 序列中该位置的数在 (B) 序列中出现了。

    数据范围

    (2≤n≤1000000)(1≤q≤10)(A) 为一个排列,(B)(A) 的非空子序列,且 (B≠A)

    思路

    可以先看看样例和解释。

    我们可以枚举每一个可能要被删除的点。若其要被删除,向左扩展到第一个比他小的点 (l),向右扩展到地一个比他小的 (r),那么这两个点构成的开区间 ((l,r)) 就是这个点要被删除时的极大区间。由于要保证必须满足条件,所以要在所有的极大区间中取最小,即为所要求的 (x)

    维护区间大小或者联通性之类的这种东西,很容易可以想到并查集。可以对下标开两个并查集,分别向左向右扩展。

    比如要找到左边第一个比当前点小的点,需要把数从大到小加入,用并查集维护不用删除的点,也就是 (B) 序列中的每个 (1), 如果遇到 (1) ,则 (fa[i]=i) ,否则 (fa[i]= ext{Find}( i-1 )) 。显然最后查询的时候需要跳过 (1) 。向右扩展同理。这样你每次都能找到极大区间,只需要取个 (min) 即可。

    一开始用前缀和维护一下 (1) 的个数,此点对应的极大区间就是扩展后的区间中 (1) 的个数加上自己((+1))。

    代码

    建议改成:三目运算符带师

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn=1e6+10;
    const int INF=0x3f3f3f3f;
    int n,ans;
    int a[maxn],pos[maxn],L[maxn],R[maxn],sum[maxn];
    char s[maxn];
    
    inline int read(){
        int x=0,fopt=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar())if(ch=='-')fopt=-1;
        for(;isdigit(ch);ch=getchar())x=(x<<3)+(x<<1)+ch-48;
        return x*fopt;
    }
    
    int Find(int x,int fa[]){
        return x==fa[x]?x:(fa[x]=Find(fa[x],fa));
    }
    
    inline void Solve(){
        for(int i=1;i<=n;i++)
            sum[i]=(s[i]=='1')?sum[i-1]+1:sum[i-1];
        ans=INF;R[n+1]=n+1;
        for(int i=1;i<=n;i++)
            L[i]=(s[i]=='1')?i:Find(i-1,L);
        for(int i=n;i>=1;i--)
            R[i]=(s[i]=='1')?i:Find(i+1,R);
        for(int i=n;i>=1;i--){
            int v=pos[i];
            if(s[v]=='1'){
                L[v]=Find(v-1,L);
                R[v]=Find(v+1,R);
            }else ans=min(ans,sum[Find(v,R)-1]-sum[Find(v,L)]+1);//注意是开区间
        }
    }
    
    int main(){
        n=read();
        for(int i=1;i<=n;i++){
            a[i]=read();
            pos[a[i]]=i;
        }
        int Q=read();
        while(Q--){
            scanf("%s",s+1);
            Solve();
            printf("%d
    ",ans);
        }
        return 0;
    }
    
  • 相关阅读:
    【回顾整理】HTML+CSS个的两个实战项目
    【转】tkinter实现的文本编辑器
    迟到的tkinter---学校选课刷屏器
    调用有道翻译API
    【leetCode】3Sum Closest
    【LeedCode】3Sum
    【LeedCode】String to integer(atoi)
    【LeetCode】Reverse digits of an integer
    前端工程师必备PS技能
    【LeetCode】Add Two Numbers
  • 原文地址:https://www.cnblogs.com/Midoria7/p/13526205.html
Copyright © 2011-2022 走看看