Comet OJ - Contest #15 題解

傳送門node

\(A\)

咕咕c++

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\n",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\n",res);
    return 0;
}

\(C\)

首先確定存在一個分界點,知足前面是\(A\)掉的,後面是沒交過或者fst的,記最後一個\(A\)掉的人爲\(i\),那麼\(i\)以及以前要知足\(a_i\)遞增,\(i\)以後的要能分紅兩個集合,一個是fst的,一個是沒交的,兩個都要知足\(a_i\)遞增,且fst的全部人的編號都小於沒交的人的編號,同時任意一個\(a_j<a_i\)\(j\)都必須是fst的,直接暴力\(check\)就好了ui

//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\n",l,r);
    }
    return 0;
}

\(D\)

這個數字\(s\)要能被表示成若干個\({10^k-1\over 9}\)之和,那麼就是\(9s\)要能表示成若干個\(10^k-1\)之和,咱們枚舉數字個數\(p\),那麼就是\(9s+p\)能被表示成\(10^k\)之和,條件就是\(p\)大於等於全部數位之和,且因爲一次進位是讓某一位-10,另外一位+1,因此還要知足\(p\)和全部數位之和在模\(9\)意義下相等。顯然\(p\)\(O(|s|)\)級別的,根據\(01\)計算器的原理,複雜度\(O(|s|)\)this

//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\n",calc());
    }
    return 0;
}

\(E\)

對於某一個元素,咱們把對他進行的全部操做放在時間軸上,一個push記爲+1,一個pop記爲-1,那麼一次時間t時的query,就是找到一個最大的i,知足[i,t]之和大於等於pos,那麼這個i處確定是一個push,且這個push的元素即爲答案了spa

那麼對於區間push和區間pop直接離線,而後就能維護每一個元素的全部操做的時間軸了code

代碼裏實現的時候略微有點不一樣,由於查詢[i,t]太難寫了,因此我代碼裏是把時間軸反過來,而後查詢一個最小的知足條件的前綴和的位置的,且push記爲-1,pop記爲+1,因此看代碼的時候注意一下get

//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\n",v,ans);
            ANS[v]=a[ans];
        }
    }
    fd(i,q,1)if(ANS[i])printf("%d\n",ANS[i]);
    return 0;
}

\(F\)

對於\(C\),咱們從後往前來枚舉\(i\)並判斷\([i+1,n]\)是否可行,因爲是從後往前,那麼至關於每次往集合里加入一個數,咱們記\(ql\)\(qr\)表示sort以後,開頭最長值域和下標都遞增的長度以及結尾最長值域和下標都遞增的長度,每次用新插入的這個數更新ql和qr就好了,用平衡樹維護一下便可,代碼寫的FHQtreapit

//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\n",l,r);
    }
    return 0;
}

\(G\)

首先相似於CF840B,若是咱們已經肯定了每一個點的度數的奇偶,那麼必定能夠構造出一組合法方案class

因爲這個構造只須要一棵生成樹就能夠完成,那麼咱們把標號大邊的儘可能留在生成樹上,這樣標號小的邊就能夠所有選了

先來考慮某一棵生成樹,把能夠選的所有選完以後,就是樹上某些點爲奇某些爲偶,咱們能夠只考慮偶數點,對於任意兩個點,咱們能夠對他們路徑上的全部邊取反,從而只改變這兩個點的狀態而不改變路徑上其它點的狀態,因此可知最終的偶數點只有\(0/1\)兩種狀況

那麼再來考慮邊,咱們建一個並查集重構樹,保證序號小的邊深度淺,那麼從上到下一次考慮每條邊,選了一條邊以後就至關於對於它所鏈接的兩個連通塊中各改變一個點的狀態,咱們發現若是兩個連通塊都是偶數點爲\(0\)的狀況,這條邊選了以後最終答案必定變劣,這種狀況下不選,其餘狀況下均可以選,用樹狀數組維護一下便可

//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;
struct eg{int v,nx;}e[N<<1];int head[N],tot;
inline void add(R int u,R int v){e[++tot]={v,head[u]},head[u]=tot;}
int dfn[N],d[N],low[N],c[N],fa[N],fr[N],to[N],vis[N],bl[N],ls[N],rs[N];
int n,m,nd,cnt;
inline void chg(R int x){for(;x<=n;x+=x&-x)c[x]^=1;}
inline int qwq(R int x){R int res=0;for(;x;x-=x&-x)res^=c[x];return res;}
inline int query(R int l,R int r){return qwq(r)^qwq(l-1);}
inline int find(R int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
void dfs(int u){
    if(u<=n)return dfn[u]=low[u]=++cnt,void();
    dfn[u]=nd+1,low[u]=0;
    go(u)dfs(v),cmin(dfn[u],dfn[v]),cmax(low[u],low[v]);
}
int main(){
    freopen("testdata.in","r",stdin);
    scanf("%d%d",&n,&m),nd=n;
    fp(i,1,m)scanf("%d%d",&fr[i],&to[i]),++fr[i],++to[i];
    fp(i,1,n)fa[i]=i;
    for(R int i=m,u,v;i;--i){
        u=find(fr[i]),v=find(to[i]);
        if(u==v)vis[i]=1,d[fr[i]]^=1,d[to[i]]^=1;
        else{
            ++nd,fa[u]=fa[v]=fa[nd]=nd,ls[nd]=u,rs[nd]=v,bl[i]=nd;
            add(nd,u),add(nd,v);
        }
    }
    dfs(nd);
    fp(i,1,n)if(!d[i])chg(dfn[i]);
    fp(i,1,m)if(bl[i]){
        R int l=query(dfn[ls[bl[i]]],low[ls[bl[i]]]);
        R int r=query(dfn[rs[bl[i]]],low[rs[bl[i]]]);
        if(l||r)vis[i]=1,chg(dfn[fr[i]]),chg(dfn[to[i]]);
    }
    fp(i,1,m)putchar(vis[i]+'0');
    putchar('\n');
    return 0;
}
相關文章
相關標籤/搜索