• Codeforces Round #602 (Div. 2, based on Technocup 2020 Elimination Round 3)


    A. Math Problem

    $solution:$

    直接找右端点最小值与左端点的最大值做差比较即可,时间复杂度 $O(n)$ 。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm> 
    #define int long long
    using namespace std;
    signed main(){
        int T;
        cin>>T;
        while(T--){
            int N,l,r;
            cin>>N;
            cin>>l>>r;
            for(int i=2;i<=N;i++){
                int a,b;
                cin>>a>>b;
                l=max(l,a),r=min(r,b);
            }
            printf("%lld
    ",max(0ll,l-r));
        }return 0;
    }
    View Code

    B. Box

    $solution:$

    随便写即可,时间复杂度 $O(n)$ 。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    inline int read(){
        int f=1,ans=0;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
        return f*ans;
    }
    const int MAXN=100011;
    int N,vis[MAXN],A[MAXN],B[MAXN],T,G[MAXN];
    bool flag;
    int main(){
        T=read();
        while(T--){
            flag=1;
            N=read();
            for(int i=1;i<=N;i++) vis[i]=0;
            for(int i=1;i<=N;i++) A[i]=read();
            B[1]=A[1];vis[A[1]]=1;
            int ps=1;
            for(int i=2;i<=N;i++){
                if(A[i-1]==A[i]){
                    while(ps<=N&&vis[ps]) ps++;
                    if(ps==N+1){flag=0;break;}
                    if(ps>A[i]){flag=0;break;}
                    B[i]=ps;vis[ps]=1;
                    continue;
                }
                if(vis[A[i]]){flag=0;break;}
                B[i]=A[i];vis[A[i]]=1;
            }
            if(!flag){
                printf("-1
    ");continue;
            }
            for(int i=1;i<=N;i++) G[i]=max(G[i-1],A[i]);
            for(int i=1;i<=N;i++) flag&=(G[i]==A[i]);
            if(flag){
                for(int i=1;i<=N;i++) printf("%d ",B[i]);
                printf("
    ");
                continue;
            }
            printf("-1
    ");
        }return 0;
    }/*
    2
    5
    5 5 5 5 5
     
    */
    View Code

    C. Messy

    $solution:$

    若为 $k$ 个前缀可以构造成 $k-1$ 个 $()$ 与 $(((())))$ ,直接暴力即可,时间复杂度 $O(n)$ 。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    inline int read(){
        int f=1,ans=0;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
        return f*ans;
    }
    const int MAXN=2001;
    vector<pair<int,int> > vec;
    int T,N,K;
    char str[MAXN];
    int A[MAXN],B[MAXN];
    int main(){
    //    freopen("8.in","r",stdin);
        T=read();
        while(T--){
            vec.clear();
            N=read(),K=read();
            for(int i=1;i<=N;i++) A[i]=B[i]=0;
            for(int i=1;i<=K-1;i++){
                A[2*i-1]=1,A[2*i]=0;
            }
            int E=2*(K-1),res=(N-E)/2;
            for(int i=E+1;i<=E+res;i++) A[i]=1;
            scanf("%s",str+1);
            for(int i=1;i<=N;i++) B[i]=(str[i]=='(');
            for(int i=1;i<=N;i++){
                if(A[i]==B[i]) continue;
                int ps;
                for(int j=i+1;j<=N;j++){
                    if(B[j]==A[i]){ps=j;break;}
                }
                reverse(B+i,B+ps+1);
                vec.push_back(make_pair(i,ps));
            }
            printf("%d
    ",vec.size());
            for(int i=0;i<vec.size();i++) printf("%d %d
    ",vec[i].first,vec[i].second);
        }return 0;
    }/*
    4
    8 2
    ()(())()
    10 3
    ))()()()((
    2 1
    ()
    2 1
    )(
     
    */
    View Code

    D. Optimal Subsequences

    $solution:$

    容易发现最后子序列的选择肯定是先去权值大的,若相同取坐标靠前的,这样既可以保证和最大也可以保证字典序最小。

    询问可以离线下来线段树二分查找下标位置,时间复杂度 $O(nlog n)$ 。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<vector>
    using namespace std;
    inline int read(){
        int f=1,ans=0;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
        return f*ans;
    }
    const int MAXN=200001;
    struct Node{
        int val,id;
    }F[MAXN];
    int N,A[MAXN];
    bool cmp(Node x1,Node x2){
        if(x1.val==x2.val) return x1.id<x2.id;
        return x1.val>x2.val; 
    }
    struct Segment_Tree{
        int Ans[MAXN<<2];
        void Modify(int k,int l,int r,int ps){
            Ans[k]++;if(l==r) return;
            int mid=l+r>>1;
            if(ps<=mid) Modify(k<<1,l,mid,ps);
            if(mid<ps) Modify(k<<1|1,mid+1,r,ps);
            return;
        }
        int Query(int k,int l,int r,int W){
            if(l==r) return l;
            int mid=l+r>>1;
            if(Ans[k<<1]>=W) return Query(k<<1,l,mid,W);
            return Query(k<<1|1,mid+1,r,W-Ans[k<<1]);  
        } 
    }Segment;
    int Ans[MAXN],q; 
    vector<pair<int,int> > vec[MAXN]; 
    int main(){
        N=read();
        for(int i=1;i<=N;i++) A[i]=F[i].val=read(),F[i].id=i;
        sort(F+1,F+N+1,cmp);
        q=read();
        for(int i=1;i<=q;i++){
            int u=read(),v=read();
            vec[u].push_back(make_pair(i,v));
        }
        for(int i=1;i<=N;i++){
            Segment.Modify(1,1,N,F[i].id);
            for(int j=0;j<vec[i].size();j++){
                int p=vec[i][j].second,id=vec[i][j].first;
                Ans[id]=A[Segment.Query(1,1,N,p)];
            }
        }
        for(int i=1;i<=q;i++) printf("%d
    ",Ans[i]);return 0;
    }/*
    3
    10 20 10
    1
    2 1
    */
    View Code

    E.Arson In Berland Forest

     $solution:$

    考虑二分答案后若可以变为一开始着火点就变,最后判断是否可行。对矩形做前缀和后对于二分答案差分得到是否可行。时间复杂度 $O(nmlog n)$ 。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<vector>
    #define int long long
    using namespace std;
    inline int read(){
        int f=1,ans=0;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
        return f*ans;
    }
    const int MAXN=1000011;
    vector<int> S[MAXN],A[MAXN],F[MAXN];
    int N,M;
    char str[MAXN];
    bool ok(int x,int y){return x>=1&&x<=N&&y>=1&&y<=M;}
    int calc(int x1,int y1,int x2,int y2){return S[x2][y2]-S[x1-1][y2]-S[x2][y1-1]+S[x1-1][y1-1];}
    void Modify(int x1,int y1,int x2,int y2,int w){if(x2<N&&y2<M) F[x2+1][y2+1]+=w;F[x1][y1]+=w;if(y2<M) F[x1][y2+1]-=w;if(x2<N) F[x2+1][y1]-=w;return;}
    bool checker(int Lim){
        for(int i=1;i<=N;i++) for(int j=1;j<=M;j++) F[i][j]=0;
        for(int i=1;i<=N;i++) for(int j=1;j<=M;j++){
            int x1=i-Lim,y1=j-Lim,x2=i+Lim,y2=j+Lim;
            if(ok(x1,y1)&&ok(x2,y2)){
                if(calc(x1,y1,x2,y2)==(2*Lim+1)*(2*Lim+1)){
                    Modify(x1,y1,x2,y2,1);
                }
            }
        }
        for(int i=1;i<=N;i++) for(int j=1;j<=M;j++) F[i][j]+=F[i-1][j]+F[i][j-1]-F[i-1][j-1];
        for(int i=1;i<=N;i++) for(int j=1;j<=M;j++) if((bool)F[i][j]!=A[i][j]) return 0;
        return 1;
    }
    signed main(){
    //    freopen("10.in","r",stdin);
        N=read(),M=read();
        for(int i=0;i<=N;i++) S[i].resize(M+1),A[i].resize(M+1),F[i].resize(M+1);
        for(int i=1;i<=N;i++){
            scanf("%s",str+1);
            for(int j=1;j<=M;j++) A[i][j]=(str[j]=='X'),S[i][j]=A[i][j];
        }
        for(int i=1;i<=N;i++) for(int j=1;j<=M;j++) S[i][j]+=S[i-1][j]+S[i][j-1]-S[i-1][j-1];
        int l=0,r=N,res=0;
        while(l<=r){
            int mid=l+r>>1;
            if(checker(mid)) res=mid,l=mid+1;
            else r=mid-1;
        }printf("%lld
    ",res);int Lim=res;
        for(int i=1;i<=N;i++){
            for(int j=1;j<=M;j++){
                bool f=1;
                int x1=i-Lim,y1=j-Lim,x2=i+Lim,y2=j+Lim;
                if(ok(x1,y1)&&ok(x2,y2)){
                    if(calc(x1,y1,x2,y2)==(2*Lim+1)*(2*Lim+1)) f=0,printf("X");
                }
                if(f) printf(".");
            }printf("
    ");
        }
        return 0;
    }/*
    3 6
    XXXXXX
    XXXXXX
    XXXXXX
    */
    View Code

    F. Wrong Answer on test 233

    考虑 $O(n^2)$ $dp$ 的优化,发现当 $A_i eq A_{i+1}$ 是会对答案产生 $1$ 或 $k-2$ 的贡献。

    而我们考虑若设选择第 $i$ 个位置选择 $A_i$ 为 $-1$ ,选择 $A_{i+1}$ 为 $+1$ ,则会发现最后值大于 $0$ 与小于 $0$ 的个数相同,因为可以对于每个 $+1$ 变为 $-1$ ,$-1$ 变为 $+1$ ,两个方案互相对应,则考虑容斥得到值等于 $0$ 的方案数 $Ans$ ,答案即为 $dfrac{k^n-Ans}{2}$ 。

    而 $Ans=sum_{i} dbinom{cnt}{i}cdotdbinom{cnt-i}{i}cdot (k-2)^{cnt-2*i}cdot k^{n-cnt}$ 。

    时间复杂度 $O(n)$ 。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #define int long long
    #define mod 998244353
    using namespace std;
    inline int read(){
        int f=1,ans=0;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
        return f*ans;
    }
    const int MAXN=200001;
    int fac[MAXN],ifac[MAXN],N,K,inv[MAXN],cnt,Ans,A[MAXN<<1],pw1[MAXN],pw2[MAXN];
    int C(int a,int b){return fac[a]*ifac[b]%mod*ifac[a-b]%mod;}
    int Mod(int x){return ((x%mod)+mod)%mod;}
    int ksm(int a,int b){
        int ans=1;
        while(b){if(b&1) ans*=a,ans%=mod;a*=a,a%=mod;b>>=1;}
        return ans;
    }
    signed main(){
    //    freopen("1.txt","r",stdin);
        N=read(),K=read();
        inv[1]=1;for(int i=2;i<MAXN;i++) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
        fac[0]=1;for(int i=1;i<MAXN;i++) fac[i]=fac[i-1]*i%mod;
        ifac[0]=1;for(int i=1;i<MAXN;i++) ifac[i]=ifac[i-1]*inv[i]%mod;
        pw1[0]=pw2[0]=1;for(int i=1;i<MAXN;i++) pw1[i]=pw1[i-1]*K%mod,pw2[i]=pw2[i-1]*(K-2)%mod;;
        Ans=ksm(K,N);for(int i=1;i<=N;i++) A[i]=A[i+N]=read();
        for(int i=1;i<=N;i++) cnt+=(A[i]!=A[i+1]);int res=0;
        for(int i=0;;i++){
            if(cnt<2*i) break;
            res+=C(cnt,i)*C(cnt-i,i)%mod*pw2[cnt-2*i]%mod*pw1[N-cnt]%mod;
            res%=mod;
        }
        Ans=Mod(Ans-res);printf("%lld
    ",Ans*inv[2]%mod);return 0;
    }/*
    6 2
    1 1 2 2 1 1
    */ 
    View Code
  • 相关阅读:
    P1182 数列分段`Section II`
    算法整理:Floyd_多源最短路
    【FBI WARNING】递归(高级数据结构的基础)
    【FBI WARNING】DP 从看透到看开
    两个例题
    结构体
    环状序列(Circular Sequence, ACM/ICPC Seoul 2004, UVa1584)
    生成元(Digit Generator, ACM/ICPC Seoul 2005, UVa1583)
    猜数字游戏的提示(Master-Mind Hints, UVa 340)
    回文词(Palindromes, UVa401)
  • 原文地址:https://www.cnblogs.com/si-rui-yang/p/11931123.html
Copyright © 2020-2023  润新知