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\n",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\n");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("\n");
            continue;
        }
        printf("-1\n");
    }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\n",vec.size());
        for(int i=0;i<vec.size();i++) printf("%d %d\n",vec[i].first,vec[i].second);
    }return 0;
}/*
4
8 2
()(())()
10 3
))()()()((
2 1
()
2 1
)(
 
*/
View Code

D. Optimal Subsequences

$solution:$

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

询问可以离线下来线段树二分查找下标位置,时间复杂度 $O(n\log 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\n",Ans[i]);return 0;
}/*
3
10 20 10
1
2 1
*/
View Code

E.Arson In Berland Forest

 $solution:$

考虑二分答案后若可以变为一开始着火点就变,最后判断是否可行。对矩形做前缀和后对于二分答案差分得到是否可行。时间复杂度 $O(nm\log 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\n",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("\n");
    }
    return 0;
}/*
3 6
XXXXXX
XXXXXX
XXXXXX
*/
View Code

F. Wrong Answer on test 233

考虑 $O(n^2)$ $dp$ 的优化,发现当 $A_i\neq 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}\cdot\dbinom{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\n",Ans*inv[2]%mod);return 0;
}/*
6 2
1 1 2 2 1 1
*/ 
View Code

 

posted @ 2019-11-25 22:12  siruiyang_sry  阅读(210)  评论(0编辑  收藏  举报