Comet OJ - Contest #15 题解

Posted yuanquming

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Comet OJ - Contest #15 题解相关的知识,希望对你有一定的参考价值。

传送门

(A)

咕咕

const int N=1005;
int a[N],n,T;
int main(){
    for(scanf("%d",&T);T;--T){
        scanf("%d",&n);
        fp(i,1,10)a[i]=n%10,n/=10;
        R int fl=1;
        fp(i,1,9)if(a[i]<a[i+1]){fl=0;break;}
        if(!fl)puts("Impossible");
        else printf("%d
",a[1]);
    }
    return 0;
}

(B)

枚举内心,那么三个点合法当且仅当到这个内心距离相同,组合数算一下就行了

typedef long long ll;
const int N=2005;
int x[N],y[N],n;ll res,dis[N];
inline ll d(R int i,R int j){return 1ll*(x[i]-x[j])*(x[i]-x[j])+1ll*(y[i]-y[j])*(y[i]-y[j]);}
inline ll calc(R int x){return 1ll*x*(x-1)*(x-2)/6;}
int main(){
    scanf("%d",&n);
    fp(i,1,n)scanf("%d%d",&x[i],&y[i]);
    fp(i,1,n){
        R int tot=0;
        fp(j,1,n)if(i!=j)dis[++tot]=d(i,j);
        sort(dis+1,dis+1+tot);
        for(R int l=1,r=1;l<=tot;l=r){
            while(r<=tot&&dis[r]==dis[l])++r;
            res+=calc(r-l);
        }
    }
    printf("%lld
",res);
    return 0;
}

(C)

首先肯定存在一个分界点,满足前面是(A)掉的,后面是没交过或者fst的,记最后一个(A)掉的人为(i),那么(i)以及之前要满足(a_i)递增,(i)之后的要能分成两个集合,一个是fst的,一个是没交的,两个都要满足(a_i)递增,且fst的所有人的编号都小于没交的人的编号,同时任意一个(a_j<a_i)(j)都必须是fst的,直接暴力(check)就行了

//quming
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const int N=505;
int a[N],stx[N],sty[N],id[N],fl[N],fr[N],tx,ty,n,T,l,r;
bool ck(int l,int r,int tt){
    if(l>=r)return 1;
    int top=0;
    fp(i,l,r)id[++top]=i;
    sort(id+1,id+1+top,[](const int &x,const int &y){return a[x]<a[y];});
    fl[0]=fr[top+1]=1,id[0]=l-1,id[top+1]=r+1;
    fp(i,1,top)fl[i]=fl[i-1]&(id[i]>id[i-1]);
    fd(i,top,1)fr[i]=fr[i+1]&(id[i]<id[i+1]);
    fp(i,tt,top)if(fl[i]&&fr[i+1])return true;
    return false;
}
int main(){
//  freopen("testdata.in","r",stdin);
    for(scanf("%d",&T);T;--T){
        scanf("%d",&n),l=n+1,r=0;
        fp(i,1,n)scanf("%d",&a[i]);
        a[n+1]=n+1,a[0]=0;
        fp(i,0,n){
            if(i&&a[i]<a[i-1])break;
            if(ck(i+1,n,a[i]-i))cmin(l,i),cmax(r,i);
        }
        if(l>r)l=r=-1;
        printf("%d %d
",l,r);
    }
    return 0;
}

(D)

这个数字(s)要能被表示成若干个({10^k-1over 9})之和,那么就是(9s)要能表示成若干个(10^k-1)之和,我们枚举数字个数(p),那么就是(9s+p)能被表示成(10^k)之和,条件就是(p)大于等于所有数位之和,且由于一次进位是让某一位-10,另一位+1,所以还要满足(p)和所有数位之和在模(9)意义下相等。显然(p)(O(|s|))级别的,根据(01)计算器的原理,复杂度(O(|s|))

//quming
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const int N=2e6+5;
char s[N];int a[N],q[N],h,t,n,res,T,sum;
inline int min(R int x,R int y){return x<y?x:y;}
int calc(){
    fp(k,1,23333333){
        R int i=1;
        while(a[i]==9)a[i++]=0,sum-=9;
        ++a[i],++sum;
        if(k>=sum&&sum%9==k%9)return k;
    }
}
int main(){
//  freopen("testdata.in","r",stdin);
    for(scanf("%d",&T);T;--T){
        scanf("%s",s+1),n=strlen(s+1);
        fp(i,1,n)a[i]=s[n-i+1]-'0',a[i]=a[i]*9;
        fp(i,1,n-1)a[i+1]+=a[i]/10,a[i]%=10;
        for(;a[n]>9;++n)a[n+1]=a[n]/10,a[n]%=10;
        fp(i,n+1,n+233333)a[i]=0;
        sum=0;
        fp(i,1,n)sum+=a[i];
        printf("%d
",calc());
    }
    return 0;
}

(E)

对于某一个元素,我们把对他进行的所有操作放在时间轴上,一个push记为+1,一个pop记为-1,那么一次时间t时的query,就是找到一个最大的i,满足[i,t]之和大于等于pos,那么这个i处肯定是一个push,且这个push的元素即为答案了

那么对于区间push和区间pop直接离线,然后就能维护每个元素的所有操作的时间轴了

代码里实现的时候略微有点不同,因为查询[i,t]太难写了,所以我代码里是把时间轴反过来,然后查询一个最小的满足条件的前缀和的位置的,且push记为-1,pop记为+1,所以看代码的时候注意一下

//quming
#include<bits/stdc++.h>
#define R register
#define pb push_back
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const int N=2e5+5;
inline int min(R int x,R int y){return x<y?x:y;}
struct node;typedef node* ptr;
struct node{
    ptr lc,rc;int t,mn;
    inline void ppd(R int x){t+=x,mn+=x;}
    inline void pd(){if(t)lc->ppd(t),rc->ppd(t),t=0;} 
    inline void upd(){mn=min(lc->mn,rc->mn);}
}e[N<<2],*rt,*pp=e;
int a[N],n,q;
char s[15];vector<int>ad[N],ed[N],qr[N];
void build(ptr &p,int l,int r){
    p=++pp;if(l==r)return;
    int mid=(l+r)>>1;
    build(p->lc,l,mid),build(p->rc,mid+1,r);
    p->upd();
}
int K,ans,ANS[N];
void query(ptr p,int l,int r,int x){
    if(l==r)return ans=r,void();
    int mid=(l+r)>>1;p->pd();
    if(!ans&&x<=mid&&p->lc->mn<=K)query(p->lc,l,mid,x);
    if(!ans&&x<=r&&p->rc->mn<=K)query(p->rc,mid+1,r,x);
}
int get(ptr p,int l,int r,int x){
    if(l==r)return p->mn;
    int mid=(l+r)>>1;p->pd();
    return x<=mid?get(p->lc,l,mid,x):get(p->rc,mid+1,r,x);
}
void update(ptr p,int l,int r,int ql,int qr,int v){
    if(ql<=l&&qr>=r)return p->ppd(v),void();
    int mid=(l+r)>>1;p->pd();
    if(ql<=mid)update(p->lc,l,mid,ql,qr,v);
    if(qr>mid)update(p->rc,mid+1,r,ql,qr,v);
    p->upd();
}
int main(){
//  freopen("testdata.in","r",stdin);
    scanf("%d%d",&n,&q);
    build(rt,1,q);
    for(R int i=1,l,r,v,id;i<=q;++i){
        scanf("%s",s+1);
        switch(s[2]){
            case 'u':{
                scanf("%d%d%d",&l,&r,&v);
                a[q-i+1]=v,ad[l].pb(q-i+1),ed[r+1].pb(q-i+1);
                break;
            }
            case 'o':{
                scanf("%d%d",&l,&r);
                ed[l].pb(q-i+1),ad[r+1].pb(q-i+1);
                break;
            }
            case 'i':{
                scanf("%d%d",&id,&v);
                a[q-i+1]=v,qr[id].pb(q-i+1);
                break;
            }
        }
    }
    fp(i,1,n){
        for(auto v:ad[i])update(rt,1,q,v,q,-1);
        for(auto v:ed[i])update(rt,1,q,v,q,1);
        for(auto v:qr[i]){
            K=get(rt,1,q,v)-a[v],ans=0;
            query(rt,1,q,v);
//          printf("%d %d
",v,ans);
            ANS[v]=a[ans];
        }
    }
    fd(i,q,1)if(ANS[i])printf("%d
",ANS[i]);
    return 0;
}

(F)

对于(C),我们从后往前来枚举(i)并判断([i+1,n])是否可行,由于是从后往前,那么相当于每次往集合里加入一个数,我们记(ql)(qr)表示sort之后,开头最长值域和下标都递增的长度以及结尾最长值域和下标都递增的长度,每次用新插入的这个数更新ql和qr就行了,用平衡树维护一下即可,代码写的FHQtreap

//quming
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
unsigned int aaa=19260817;
inline unsigned int rd(){aaa^=aaa>>15,aaa+=aaa<<12,aaa^=aaa>>3;return aaa;}
const int N=2e5+5;
struct node;typedef node* ptr;
struct node{
    ptr lc,rc;int v,sz;unsigned int pr;
    inline void init(R int val){v=val,pr=rd(),sz=1;}
    inline ptr upd(){return sz=lc->sz+rc->sz+1,this;}
}e[N],*rt=e;int tot;
inline ptr newnode(R int v){return e[++tot].init(v),(e+tot)->lc=(e+tot)->rc=e,e+tot;}
void split(ptr p,int k,ptr &s,ptr &t){
    if(p==e)return s=t=e,void();
    if(p->v<=k)s=p,split(p->rc,k,p->rc,t);
        else t=p,split(p->lc,k,s,p->lc);
    p->upd();
}
ptr merge(ptr s,ptr t){
    if(s==e)return t;if(t==e)return s;
    if(s->pr<t->pr)return s->rc=merge(s->rc,t),s->upd();
    return t->lc=merge(s,t->lc),t->upd();
}
void insert(int k){
    ptr s,t;
    split(rt,k,s,t);
    rt=merge(merge(s,newnode(k)),t);
}
void erase(int k){
    ptr s,t,p;
    split(rt,k,s,t),split(s,k-1,s,p),p=merge(p->lc,p->rc);
    rt=merge(merge(s,p),t);
}
int rk(int k){
    ptr s,t;int now;
    split(rt,k-1,s,t);now=s->sz+1;
    return rt=merge(s,t),now;
}
int Kth(ptr p,int k){
    if(p->lc->sz==k-1)return p->v;
    if(p->lc->sz>=k)return Kth(p->lc,k);
    return Kth(p->rc,k-p->lc->sz-1);
}
int Pre(int k){
    ptr s,t;int now;
    split(rt,k-1,s,t),now=Kth(s,s->sz);
    return rt=merge(s,t),now;
}
int nxt(int k){
    ptr s,t;int now;
    split(rt,k,s,t),now=Kth(t,1);
    return rt=merge(s,t),now;
}
int ok[N],a[N],kr[N],n,ql,qr,T,l,r;
int main(){
//  freopen("testdata.in","r",stdin);
    for(scanf("%d",&T);T;--T){
        rt=e,tot=0;
        scanf("%d",&n),l=n+1,r=0;
        fp(i,1,n)scanf("%d",&a[i]),kr[a[i]]=i,ok[i]=0;
        a[0]=0,a[n+1]=n+1,kr[0]=0,kr[n+1]=n+1,ok[0]=ok[n+1]=0;
        ok[n+1]=1;
        insert(0),insert(n+1),ql=qr=2;
        R int cnt=2;
        fd(i,n,1){
            R int pl=Pre(a[i]),pr=nxt(a[i]);
            R int sz=rk(pl);
            if(ql>=sz){
                if(i>kr[pl]&&i<kr[pr])++ql;
                else if(i<kr[pl])ql=sz;
                else ql=sz+1;
            }
            sz=cnt-(rk(pr)-1);
            if(qr>=sz){
                if(i>kr[pl]&&i<kr[pr])++qr;
                else if(i>kr[pr])qr=sz;
                else qr=sz+1;
            }
            ++cnt;
            insert(a[i]);
            ok[i]=(ql+qr>=cnt&&ql>=a[i-1]-(i-1)+1);
        }
        fp(i,0,n){
            if(i&&a[i]<a[i-1])break;
            if(ok[i+1])cmin(l,i),cmax(r,i);
        }
        if(l>r)l=r=-1;
        printf("%d %d
",l,r);
    }
    return 0;
}

(G)

咕咕了

以上是关于Comet OJ - Contest #15 题解的主要内容,如果未能解决你的问题,请参考以下文章

Comet OJ - Contest #14题解

Comet OJ - Contest #8题解

Comet OJ - Contest #11 题解&赛后总结

Comet OJ - Contest #13 补题题解

Comet OJ - Contest #9 & X Round 3题解

Comet OJ - Contest #15