ABC392

A

B

C

模拟

void solve(){
    int n;cin>>n;
    vector<int>p(n+1);
    vector<int>q(n+1);
    vector<int>a(n+1);
    rep(i,1,n)cin>>p[i];
    rep(i,1,n){
        cin>>q[i];
        a[q[i]]=i;
    }
    rep(i,1,n){
        cout<<q[p[a[i]]]<<' ';
    }
}

D

题意:n个ki面骰子,每个面Aij,求选中两个骰子同时掷出相同的数的概率
思路:
O(NXNXlogN)STL+暴力枚举

void solve(){
    int n;cin>>n;
    vector<int>len(n+1);
    rep(i,1,n){
        int k;cin>>k;
        len[i]=k;
        rep(j,1,k){
            int x;cin>>x;
            mp[i][x]++;            
        }
    }
    long double res=0;
    rep(i,1,n){
        rep(j,1,n){
            if(i==j)continue;
            long double ans=0;
            for(auto [x,y]:mp[i]){
                ans+=(y*1.0*mp[j][x]/(len[i]*len[j]));
                // debug(ans);
            }
            res=max(res,ans);

        }
    }
    cout<<fixed<<setprecision(11)<<res<<endl;
}

E

题意:给定一个无向图,每次可以修改一条边的一个点,求把其连成连通块最少操作序列
思路:
为了操作次数最少,我们需要修改没用的边的节点(连的两个顶点已经在一个连通块)
将其塞入list里(为了减少erase的时间复杂度)
将所有连通块的代表节点遍历检查是否和该边的一个节点在同一个连通块里,如果在,就断边连上,不在就继续遍历

int f[maxn];
int find(int x){
    if(f[x]!=x){
        f[x]=find(f[x]);
    }return f[x];
}
void merge(int x,int y){
    if(find(x)!=find(y)){
        f[find(x)]=find(y);
    }
}
void solve(){
    int n,m;cin>>n>>m;
    rep(i,1,n)f[i]=i;
    vector<pii>edge(m+1);
    vector<pair<pii,int>>tt;
    rep(i,1,m){
        cin>>edge[i].fi>>edge[i].se;
        int u=edge[i].fi,v=edge[i].se;
        if(find(u)==find(v)){
            tt.pb({{u,v},i});
        }
        merge(u,v);
    }
    set<int>compo;
    rep(i,1,n){
        compo.insert(find(i));
    }
    list<int>fa;
    for(auto t:compo){
        fa.pb(t);
    }

    vector<pair<int,pii>>ans;
    for(int j=0;j<tt.size();j++){
        // int v=tt[j].fi,id=tt[j].se;
        auto[x,id]=tt[j];
        int u=x.fi,v=x.se;
        for(auto it=fa.begin();it!=fa.end();it++){
            int com=*it;
            if(find(u)!=find(com)){
                ans.pb({id,{v,com}});
                merge(u,com);
                fa.erase(it);
                break;
            }
        }
    }
    cout<<ans.size()<<endl;
    for(int i=0;i<ans.size();i++){
        cout<<ans[i].fi<<' '<<ans[i].se.fi<<' '<<ans[i].se.se<<endl;
    }
}

F

题意:从空数组开始,从1~n每次i选择一个p,将i插入到空数组的第p个位置
思路:
可以用线段树二分
trick:从后往前操作,初始全为空,发现原来的插入操作等同于插入到剩余的空的数组的第p个位置
只需要用线段树修改序列,以及查找第p个非空位置即可(1代表空位置,0代表已经占了)

struct node{
    int l,r;
    int n;
}tr[4*maxn];
void pushup(int p){
    tr[p].n=tr[ls].n+tr[rs].n;
}
void build(int p,int l,int r){
    tr[p].l=l;tr[p].r=r;
    if(l==r){
        tr[p].n=1;
        return;
    }
    int mid=l+r>>1;
    build(ls,l,mid);build(rs,mid+1,r);
    pushup(p);
}
int binary(int p,int x){
    int l=tr[p].l,r=tr[p].r;
    if(l==r){
        tr[p].n=0;return l;
    }
    int res=0;
    if(x<=tr[ls].n)res=binary(ls,x);
    else res=binary(rs,x-tr[ls].n);
    pushup(p);
    return res;
}
void solve(){
    int n;cin>>n;
    vector<int>a(n+1);
    rep(i,1,n)cin>>a[i];
    build(1,1,n);
    vector<int>ans(n+1);
    for(int i=n;i>=1;i--){
        int now=binary(1,a[i]);
        // debug(now);
        ans[i]=now;
    }
    vector<int>res(n+1);
    rep(i,1,n){
        // cout<<ans[i]<<' ';
        res[ans[i]]=i;
    }
    rep(i,1,n){
        cout<<res[i]<<' ';
    }
    cout<<endl;
}
posted @ 2025-06-12 22:26  Marinaco  阅读(20)  评论(0)    收藏  举报
//雪花飘落效果