AtCoder Beginner Contest 441题解

D - Paid Walk

简单dfs

int n,m,s,l,t;
vector<int>ans;
vector<pii>g[N];
void dfs(int u,int cs,int st){
    if(cs>t)return;
    if(st==l){
        if(cs>=s&&cs<=t)ans.push_back(u);
        return;
    }
    for(auto [v,w]:g[u]){
        dfs(v,cs+w,st+1);
    }
}
void solve(){
    cin>>n>>m>>l>>s>>t;
    int u,v,w;
    up(i,1,m){
        cin>>u>>v>>w;
        g[u].push_back({v,w});
    }
    dfs(1,0,0);
    sort(ans.begin(),ans.end());
    ans.erase(unique(ans.begin(),ans.end()),ans.end());
    for(auto x:ans)cout<<x<<" ";
}

E - A > B substring

可以将其映射到一个二位平面上,遇到 A 视为 +1,B 视为 -1,固定 i 位左端点,找后面有多少个数比a[i]大,求固定区间一个数的排名,平衡树很容易被想到。

int n;
string s;
int a[N];
struct FHQTreap{
    int cnt=0,root=0;
    struct node{
        int ls,rs;
        int key,pri;
        int siz;
    }tr[N];
    int ans;
    inline void build(int x){
        cnt++;
        tr[cnt].siz=1;
        tr[cnt].ls=tr[cnt].rs=0;
        tr[cnt].key=x;
        tr[cnt].pri=rand();
    }
    inline void push_up(int k){
        tr[k].siz=tr[tr[k].ls].siz+tr[tr[k].rs].siz+1;
    }
    inline void split(int u,int x,int &l,int &r){
        if(u==0){l=r=0;return;}
        if(tr[u].key<=x){
            l=u;
            split(tr[u].rs,x,tr[u].rs,r);
        }
        else{
            r=u;
            split(tr[u].ls,x,l,tr[u].ls);
        }
        push_up(u);
    }
    inline int merge(int l,int r){
        if(l==0||r==0)return l+r;
        if(tr[l].pri>tr[r].pri){
            tr[l].rs=merge(tr[l].rs,r);
            push_up(l);
            return l;
        }
        else{
            tr[r].ls=merge(l,tr[r].ls);
            push_up(r);
            return r;
        }
    }
    inline void insert(int x){
        int l,r;
        split(root,x,l,r);
        build(x);
        root=merge(merge(l,cnt),r);
    }
    inline void del(int x){
        int l,r,p;
        split(root,x,l,r);
        split(l,x-1,l,p);
        p=merge(tr[p].ls,tr[p].rs);
        root=merge(merge(l,p),r);
    }
    inline int getrank(int x){
        int l,r;
        split(root,x-1,l,r);
        int last=tr[l].siz+1;
        root=merge(l,r);
        return last;
    } 
    inline int kth(int u,int k){
        if(k==tr[tr[u].ls].siz+1)return u;
        if(k<=tr[tr[u].ls].siz)return kth(tr[u].ls,k);
        else return kth(tr[u].rs,k-tr[tr[u].ls].siz-1);
    }
    inline int getpre(int x){
        int l,r;
        split(root,x-1,l,r);
        int last=tr[kth(l,tr[l].siz)].key;
        root=merge(l,r);
        return last;
    }
    inline int getpre1(int x){
        int l,r;
        split(root,x,l,r);
        int last=tr[kth(l,tr[l].siz)].key;
        root=merge(l,r);
        return last;
    }
    inline int getnxt(int x){
        int l,r;
        split(root,x,l,r);
        int last=tr[kth(r,1)].key;
        root=merge(l,r);
        return last;
    }
    inline int size(){
        return tr[root].siz;
    }
    inline int getans(int x){
        int a=getpre1(x),b=getnxt(x);
        if(x-a>b-x)return b;
        else return a;
    }
}T;

void solve(){
    cin>>n>>s;
    s=" "+s;
    up(i,1,n){
        if(s[i]=='A')a[i]=a[i-1]+1;
        if(s[i]=='B')a[i]=a[i-1]-1;
        if(s[i]=='C')a[i]=a[i-1];
        T.insert(a[i]);
    }
    int ans=0,pos=n;
    up(i,1,n){
        ans+=pos-T.getrank(a[i-1]+1)+1;
        T.del(a[i]);
        pos--;
    }
    cout<<ans;
}

F - Must Buy

一个经典的trick,分别求前缀和后缀就行了。
注意,二维背包和一维背包有一点区别,p[i]之前的要继承。

int n,m;
int f[1005][N],g[1005][N];
int p[1050],v[1050];
void solve(){
    cin>>n>>m;
    up(i,1,n){
        cin>>p[i]>>v[i];
    }
    up(i,1,n){
        dn(j,m,0){
            f[i][j]=max(f[i][j],f[i-1][j]);
            if(j>=p[i])f[i][j]=max(f[i-1][j-p[i]]+v[i],f[i][j]);
        }
    }
    dn(i,n,1){
        dn(j,m,0){
            g[i][j]=max(g[i][j],g[i+1][j]);
            if(j>=p[i])g[i][j]=max(g[i+1][j-p[i]]+v[i],g[i][j]);
        } 
    }
    int ans=f[n][m];
    up(i,1,n){
        int maxl=0,maxl2=0;
        up(j,0,m){
            maxl=max(maxl,f[i-1][j]+g[i+1][m-j]);
            if(j>=p[i])maxl2=max(maxl2,v[i]+f[i-1][j-p[i]]+g[i+1][m-j]);
        }
        if(maxl2==ans&&maxl<ans)cout<<"A";
        if(maxl2==ans&&maxl==ans)cout<<"B";
        if(maxl==ans&&maxl2<ans)cout<<"C";
    }
}
posted @ 2026-03-18 22:49  LiQXing  阅读(1)  评论(0)    收藏  举报