算法竞赛训练实录

不问归期 提交于 2019-12-22 01:50:51

Codeforces Round 603

4题 rank1985

ABCD

都是很水的题。 cout << 000输出0,而cout<<"000"才输出000,因为这个WA6次要被笑(打)死。

E

判定括号序列合法性:每一个前缀和不小于0,同时最后一个前缀和等于0.线段树更新即可.新技能Get.

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
int minz[maxn*4],tg[maxn*4],maxz[maxn*4],tg2[maxn*4];
char s[maxn];
inline int ls(int x){
    return x<<1;
}
inline int rs(int x){
    return x<<1|1;
}
void pushdown(int rt){
    if(tg[rt]==0) return;
    minz[ls(rt)]+=tg[rt];
    tg[ls(rt)]+=tg[rt];
    minz[rs(rt)]+=tg[rt];
    tg[rs(rt)]+=tg[rt];
    tg[rt]=0;
}
void pushdown2(int rt){
    if(tg2[rt]==0) return;
    maxz[ls(rt)]+=tg2[rt];
    tg2[ls(rt)]+=tg2[rt];
    maxz[rs(rt)]+=tg2[rt];
    tg2[rs(rt)]+=tg2[rt];
    tg2[rt]=0;
}
int upd(int il,int ir,int d,int rt,int l,int r){
    if(il>r||ir<l) return minz[rt];
    if(l>=il&&r<=ir){
        minz[rt]+=d;
        tg[rt]+=d;
        return minz[rt];
    }
    pushdown(rt);
    int mid=(l+r)>>1;
    return minz[rt]=min(upd(il,ir,d,ls(rt),l,mid),upd(il,ir,d,rs(rt),mid+1,r));
}
int ask(int il,int ir,int rt,int l,int r){
    if(il>r||ir<l) return 0x3f3f3f3f;
    if(l>=il&&r<=ir) return minz[rt];
    pushdown(rt);
    int mid=(l+r)>>1;
    return min(ask(il,ir,ls(rt),l,mid),ask(il,ir,rs(rt),mid+1,r));
}
int upd2(int il,int ir,int d,int rt,int l,int r){
    if(il>r||ir<l) return maxz[rt];
    if(l>=il&&r<=ir){
        maxz[rt]+=d;
        tg2[rt]+=d;
        return maxz[rt];
    }
    pushdown2(rt);
    int mid=(l+r)>>1;
    return maxz[rt]=max(upd2(il,ir,d,ls(rt),l,mid),upd2(il,ir,d,rs(rt),mid+1,r));
}
int ask2(int il,int ir,int rt,int l,int r){
    if(il>r||ir<l) return 0;
    if(l>=il&&r<=ir) return maxz[rt];
    pushdown2(rt);
    int mid=(l+r)>>1;
    return max(ask2(il,ir,ls(rt),l,mid),ask2(il,ir,rs(rt),mid+1,r));
}
int st[maxn];
int main(){
    int n;
    scanf("%d",&n);
    scanf("%s",s+1);
    int cur=1;
    for(int i=1;i<=n;i++){
        if(s[i]=='L') cur=max(1,cur-1);
        else if(s[i]=='R') {
            cur++;
        }
        else if(s[i]=='(') {
            if(st[cur]==1) ;
            else if(st[cur]==0){
                st[cur]=1;
                upd(cur,n,1,1,1,n);
                upd2(cur,n,1,1,1,n);
            }
            else {
                st[cur]=1;
                upd(cur,n,2,1,1,n);
                upd2(cur,n,2,1,1,n);
            }
        }
        else if(s[i]==')'){
            if(st[cur]==-1);
            else if(st[cur]==0){
                st[cur]=-1;
                upd(cur,n,-1,1,1,n);
                upd2(cur,n,-1,1,1,n);
            }
            else {
                st[cur]=-1;
                upd(cur,n,-2,1,1,n);
                upd2(cur,n,-2,1,1,n);
            }
        }
        else{
            if(st[cur]==0) ;
            else if(st[cur]==1){
                st[cur]=0;
                upd(cur,n,-1,1,1,n);
                upd2(cur,n,-1,1,1,n);
            }
            else {
                st[cur]=0;
                upd(cur,n,1,1,1,n);
                upd2(cur,n,1,1,1,n);
            }
        }
        if(ask(1,n,1,1,n)>=0&&ask(n,n,1,1,n)==0){
            printf("%d ", ask2(1,n,1,1,n));
        }
        else printf("-1 ");
    }
    return 0;
}

Codeforces Round 604

4题 rank 252

B

单调栈正反扫一遍,找每个数左边和右边第一个比它大的数的位置,位置之差等于它本身则成立,否则不成立。

似乎有更简单的做法。。懒得看了

#include <bits/stdc++.h>
using namespace std;
char ans[200005];
int a[200005];
int stk[200005],id[200005];
int l[200005],r[200005],pos[200005];
int main(){
    int T;
    cin >> T;
    while(T--){
        int n;
        cin >> n;
        for(int i=1;i<=n;i++) cin >> a[i],pos[a[i]]=i;
        int hd=0;
        int i=1;
        stk[0]=0x3f3f3f3f;  id[0]=0;
        while(i<=n){
            while(stk[hd]<a[i]) hd--;
            l[i]=id[hd]+1;
            stk[++hd]=a[i];
            id[hd]=i;
            i++;
        }
        i=n; hd=0; id[0]=n+1;
        while(i>0){
            while(stk[hd]<a[i]) hd--;
            r[i]=id[hd]-1;
            stk[++hd]=a[i];
            id[hd]=i;
            i--;
        }
        for(i=1;i<=n;i++){
            int j=pos[i];
            if(r[j]-l[j]+1==i) ans[i]='1';
            else ans[i]='0';
        //  cout << l[i] << " " << r[i] << endl;
        }
        for(i=1;i<=n;i++) cout << ans[i];
        cout << endl;
    }
    return 0;
}

E

简单递推题,居然花了大段时间求无穷级数(居然还没求出来)。。。

\(f(x)\)为到第\(x\)天的期望,那么显然有\(f(x)=p(i-1)*(f(x-1)+1)+(1-p(i-1))*(f(x)+f(x-1)+1)\)

解得 \(f(x)=(f(x-1)+1)/p(i-1)\) 求出\(f(n+1)\)即可

#include <bits/stdc++.h>
using namespace std;
const int mod=998244353;
int qpow(int x,int y){
    int res=1,bas=x;
    while(y){
        if(y&1) res=1ll*res*bas%mod;
        bas=1ll*bas*bas%mod;
        y>>=1;
    }
    return res%mod;
}
int p[200005];
int dp[200005];
int main(){
    int n;
    cin >> n;
    for(int i=1;i<=n;i++) cin >> p[i];
    dp[1]=0;
    for(int i=2;i<=n+1;i++){
        dp[i]=(1ll*(dp[i-1]+1)*qpow(p[i-1],mod-2)%mod)*100%mod;
    }
    cout << dp[n+1];
    return 0;
} 

codeforces EDU round 78

3题rk891

A

memcmp函数返回值:相等为0,小于时小于0,大于时大于0

B

猜想:对于\(1\)\(n\)的和\(\frac{n*(n+1)}{2}\),对于任意\(0\leq s \leq \frac{n*(n+1)}{2}\),总能找到\(1\)\(n\)的子集,使其元素和为\(s\).

证明:\(s\)有两种情况:1)小于等于\(n\),问题解决;2)大于\(n\),则将\(s\)减去\(n\),此时\(s\)小于等于\(1\)到n-1的和,问题转化为1到n-1的情况;如此递归下去,得证。

C

枚举左边,判断右边,map维护

D

左端点排序,扫描线从左到右即可。

不会T的理由是并查集至多合并\(n\)次就一定可以break出来

#include <bits/stdc++.h>
using namespace std;
struct node{
    int l,r;
}p[500005];
int id[1000005];
set<int> sr;
int fa[500005];
int find(int x){
    if(fa[x]==x) return x;
    return fa[x]=find(fa[x]);
}
bool cmp(node x,node y){
    return x.l<y.l;
}
bool join(int u,int v){
    int x=find(u),y=find(v);
    if(x==y) return false;
    fa[x]=y;
    return true;
}
int main(){
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++) {
        scanf("%d%d",&p[i].l,&p[i].r);
        fa[i]=i;
    }
    sort(p+1,p+n+1,cmp);
    for(int i=1;i<=n;i++) id[p[i].l]=id[p[i].r]=i;
    sr.insert(p[1].r);
    bool ff=true;
    for(int i=2;i<=n;i++){
        set<int>::iterator it = sr.begin();
        vector<int> tmp;
        for(;it!=sr.end();it++){
            if(p[i].l>*it) {
                tmp.push_back(*it);
            }
            else break;
        }
        for(int j=0;j<int(tmp.size());j++) sr.erase(tmp[j]);
        it=sr.begin();
        bool f=true;
        for(;it!=sr.end();it++){
            if(p[i].r>*it){
                f=join(i,id[*it]);
            }
            else break;
            if(!f){
                break;
            }
        }
        if(!f){
            ff=false;
            break;
        }
        sr.insert(p[i].r);
    }
    int cnt=0;
    for(int i=1;i<=n;i++) if(find(i)==i) cnt++;
    if(cnt>1) ff=false;
    if(ff) cout << "YES\n";
    else cout << "NO\n";
    return 0;
} 
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!