1. 程式人生 > >Educational Codeforces Round 23 補題小結

Educational Codeforces Round 23 補題小結

stack Education codeforce log add 介紹 二分答案 str etc

昨晚聽說有教做人場,去補了下玩。

大概我的水平能做個5/6的樣子?

(不會二進制Trie啊,我真菜)

A.

傻逼題。大概可以看成向量加法,判斷下就好了。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
int x1,x2,yy1,y2,x,y;
int main(){
    scanf("%d%d%d%d%d%d",&x1,&yy1,&x2,&y2,&x,&y);
    
int dx=abs(x1-x2),dy=abs(yy1-y2); if((abs(dx/x-dy/y)%2==0)&&(dx%x==0)&&(dy%y==0))puts("YES"); else puts("NO"); }

B.

找符合要求的最小三元組乘積出現次數。

sort一下隨便搞搞就行了。

#include<bits/stdc++.h>
#define N 100010
typedef long long ll;
using namespace std;
ll a[N];int n;ll minv;
inline ll read(){
    ll f
=1,x=0;char ch; do{ch=getchar();if(ch==-)f=-1;}while(ch<0||ch>9); do{x=x*10+ch-0;ch=getchar();}while(ch>=0&&ch<=9); return f*x; } int main(){ n=read(); for(int i=1;i<=n;i++)a[i]=read(); sort(a+1,a+n+1);ll cnt=0; for(int i=1;i<=n;i++)if(a[i]==a[3
])cnt++; if(a[1]==a[3])cout<<(cnt-2)*(cnt-1)*cnt/6<<endl; else if(a[2]==a[3])cout<<(cnt-1)*cnt/2<<endl; else cout<<cnt<<endl; }

C.

第一反應數位dp,反正也可做。

數位記憶化搜索大概也行的樣子。

但是可以顯然地證明一個性質:x?+?1?-?sumd(x?+?1)?≥?x?-?sumd(x)

這就滿足了一個單調性,按照出題人的想法是可以二分答案。

但是可以直接枚舉最大的範圍嘛!幹嘛非要寫個二分答案

而且這麽寫跑得飛快。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,s;
inline bool check(ll x){
    ll res=x;
    while(res){x-=res%10;res/=10;}
    return x>=s;
}
int main(){
    cin>>n>>s;ll maxv=min(n,s+180),sum=0;
    for(ll i=s;i<=maxv;i++)if(check(i))++sum;
    cout<<n-maxv+sum<<endl;
}

D.

用單調棧維護一個"一個數向左向右最大可以做max與min能管的距離"

好久不上語文課了表達能力=0

實在不行看官方題解吧。

#include<bits/stdc++.h>
#define N 1000005
#define inf 1000000007
typedef long long ll;
using namespace std;
int n,a[N];
ll ans1,ans2,ans;
stack<int>s1,s2;
inline int read(){
    int f=1,x=0;char ch;
    do{ch=getchar();if(ch==-)f=-1;}while(ch<0||ch>9);
    do{x=x*10+ch-0;ch=getchar();}while(ch>=0&&ch<=9);
    return f*x;
}
int main(){
    n=read();
    s1.push(0);s2.push(0);
    for(int i=1;i<=n;i++){
        a[i]=read();a[0]=0;
        while(s1.top()&&a[i]<a[s1.top()]){
            int top=s1.top();s1.pop();
            ans1-=1LL*a[top]*(top-s1.top());
        }
        ans1+=1LL*a[i]*(i-s1.top());s1.push(i);
        a[0]=inf;
        while(s2.top()&&a[i]>a[s2.top()]){
            int top=s2.top();s2.pop();
            ans2-=1LL*a[top]*(top-s2.top());
        }
        ans2+=1LL*a[i]*(i-s2.top());s2.push(i);
        ans+=ans2-ans1;
    }
    cout<<ans<<endl;
}


E.

我太菜了,以前居然沒見過這種在二進制字典樹上的貪心……

建一個二進制的字典樹,然後貪心一下看能不能搞成1就行了。

具體的我日後可能得寫個blog介紹下Trie的貪心。

#include<bits/stdc++.h>
#define N 3000005
using namespace std;
int size[N],ch[N][2],n,cnt,a,b,type;
inline void ins(int x,int add){
    int now=1;
    for(int i=26;i>=0;i--){
        bool v=((x>>i)&1);
        if(!ch[now][v])ch[now][v]=++cnt;
        now=ch[now][v];
        size[now]+=add;
    }
}
inline void query(int x,int y){
    int ans=0,now=1,val=0;
    for(int i=26;i>=0&&now;i--){
        bool xbit=((x>>i)&1),ybit=((y>>i)&1);
        val+=val;
        if(ybit){
            ans+=size[ch[now][xbit]];now=ch[now][!xbit];
            val+=!xbit;
        }
        else{now=ch[now][xbit];val+=xbit;}
    }
    printf("%d\n",ans);
}
inline int read(){
    int f=1,x=0;char ch;
    do{ch=getchar();if(ch==-)f=-1;}while(ch<0||ch>9);
    do{x=x*10+ch-0;ch=getchar();}while(ch>=0&&ch<=9);
    return f*x;
}
int main(){
    cnt=1;n=read();
    while(n--){
        int opt=read(),x=read();
        if(opt==1)ins(x,1);
        if(opt==2)ins(x,-1);
        if(opt==3){
            int y=read();
            query(x,y);
        }
    }
}

F.

看到mex突然激動,感覺可能是個DS題。

果然是。

第一反應主席樹求一下就好,後來想下,主席樹也是沒有必要的。

直接線段樹維護就行。

類似於取反,求最左節點的操作。

值域過大可以選擇動態開點或者離散化。

我就寫了個離散化……

類似的分解的操作的題bzoj都有,如果一下子看不懂這篇

可以QQ找我問幾個原題。

#include<bits/stdc++.h>
#define N 300005
#define lson (o<<1)
#define rson (o<<1|1)
using namespace std;
typedef long long ll;
ll a[N];
struct Query{ll l,r,opt;}Q[N];
int n,len;
struct Segment_Tree{
    int sumv[N<<4],addv[N<<4],rev[N<<4];
    inline void pushup(int o){sumv[o]=sumv[lson]+sumv[rson];}
    inline void puttag(int o,int l,int r,int add,int re){
        if(re){
            if(addv[o]==-1)rev[o]^=1,sumv[o]=r-l+1-sumv[o];
            else addv[o]^=1,sumv[o]=r-l+1-sumv[o];
        }
        else if(add!=-1){
            rev[o]=0;addv[o]=add;sumv[o]=(r-l+1)*add;
        }
    }
    inline void pushdown(int o,int l,int r){
        int mid=(l+r)>>1;
        puttag(lson,l,mid,addv[o],rev[o]);
        puttag(rson,mid+1,r,addv[o],rev[o]);
        addv[o]=-1;rev[o]=0;
    }
    void build(int o,int l,int r){
        if(l==r){addv[o]=-1;return;}
        int mid=(l+r)>>1;
        build(lson,l,mid);build(rson,mid+1,r);
        addv[o]=-1;
    }
    int querymex(int o,int l,int r){
        if(l==r)return l;
        int mid=(l+r)>>1;pushdown(o,l,r);
        if(sumv[lson]<mid-l+1)return querymex(lson,l,mid);
        else return querymex(rson,mid+1,r);
    }
    void change(int o,int l,int r,int ql,int qr,int add,int re){;
        if(ql<=l&&r<=qr){puttag(o,l,r,add,re);return;}
        int mid=(l+r)>>1;pushdown(o,l,r);
        if(ql<=mid)change(lson,l,mid,ql,qr,add,re);
        if(qr>mid)change(rson,mid+1,r,ql,qr,add,re);
        pushup(o);
    }
}T;
inline ll read(){
    ll f=1,x=0;char ch;
    do{ch=getchar();if(ch==-)f=-1;}while(ch<0||ch>9);
    do{x=x*10+ch-0;ch=getchar();}while(ch>=0&&ch<=9);
    return f*x;
}
int main(){
    n=read();
    for(int i=1;i<=n;i++){
        Q[i].opt=read();Q[i].l=read();Q[i].r=read();
    }
    a[1]=1;
    for(int i=1;i<=n;i++)a[3*i-1]=Q[i].l,a[3*i]=Q[i].r,a[3*i+1]=Q[i].r+1;
    sort(a+1,a+n*3+2);
    len=1;
    for(int i=2;i<=3*n+1;++i)if(a[i]!=a[i-1]) a[++len]=a[i];
    T.build(1,1,len);
    for(int i=1;i<=n;i++){
        int x=lower_bound(a+1,a+len+1,Q[i].l)-a,y=lower_bound(a+1,a+len+1,Q[i].r)-a;
        if(Q[i].opt==1)T.change(1,1,len,x,y,1,0);
        if(Q[i].opt==2)T.change(1,1,len,x,y,0,0);
        if(Q[i].opt==3)T.change(1,1,len,x,y,-1,1);
        printf("%lld\n",a[T.querymex(1,1,len)]);
    }
}

啊最後總結下吧。

姿勢水平還不夠,還得學習一個。

數據結構要學會活學活用,用現有的水平解決一些不是很常規的問題。

dp什麽的思維還是不夠,要學習一個。

不過這場的外國人居然出了兩個DS?

但是可能外國的DS水平不如我國?這個Trie題講道理可能在國內只有T2的難度吧。

最後一個Segment-Tree可以算奇奇怪怪的常規應用的組合。

所以還是要熟練呀~

Educational Codeforces Round 23 補題小結