2023 团体程序设计天梯赛 L1,L2,L3-2

7-1 最好的文档

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;

void solve(){
    cout<<"Good code is its own best documentation.";
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int ct=1;
    // cin>>ct;

    while(ct--){
        solve();
    }
}

7-2 什么是机器学习

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;

void solve(){
    int a,b;
    cin>>a>>b;
    cout<<a+b-16<<endl<<a+b-3<<endl<<a+b-1<<endl<<a+b;
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int ct=1;
    // cin>>ct;

    while(ct--){
        solve();
    }
}

7-3 程序员买包子

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;

void solve(){
    int n,m,k;
    string x;

    cin>>n>>x>>m>>k;

    if(k==n){
        cout<<"mei you mai "<<x<<" de";
    }
    else if(k==m){
        cout<<"kan dao le mai "<<x<<" de";
    }
    else{
        cout<<"wang le zhao mai "<<x<<" de";
    }

}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int ct=1;
    // cin>>ct;

    while(ct--){
        solve();
    }
}

7-4 进化论

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;

void solve(){
    int a,b,c;
    cin>>a>>b>>c;

    if(c==a*b){
        cout<<"Lv Yan";
    }
    else if(c==a+b){
        cout<<"Tu Dou";
    }
    else{
        cout<<"zhe du shi sha ya!";
    }

    cout<<endl;
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int ct=1;
    cin>>ct;

    while(ct--){
        solve();
    }
}

7-5 猜帽子游戏

\(f\) 记录有几个人不猜,如果 \(f>=n\) 则代表所有人都没猜。

如果某个人猜错了,则直接令 \(f=n\)

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;

void solve(){
    int n;
    cin>>n;

    vector<int> a(n+1);

    for(int i=1;i<=n;i++){
        cin>>a[i];
    }

    int k;
    cin>>k;

    while(k--){
        vector<int> b(n+1);
        int f=0;

        for(int i=1;i<=n;i++){
            cin>>b[i];
            if(b[i]==0) f++;
            else if(b[i]!=a[i]) f=n;
        }

        if(f>=n) cout<<"Ai Ya";
        else cout<<"Da Jiang!!!";

        cout<<endl;
    }
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int ct=1;
    // cin>>ct;

    while(ct--){
        solve();
    }
}

7-6 剪切粘贴

字符串题,无各种函数纯手搓。

技巧是新开一个字符串临时存储中间字符串,不要试图直接在原字符串上做操作

注意 .size() 是无符号整型,做减法可能会溢出

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;

void solve(){
    string s;
    cin>>s;

    int q;
    cin>>q;

    while(q--){
        int l,r;
        cin>>l>>r;
        l--,r--;

        string ts,t,a,b;
        for(int i=l;i<=r;i++){
            t.push_back(s[i]);
        }
        for(int i=0;i<l;i++){
            ts.push_back(s[i]);
        }
        for(int i=r+1;i<s.size();i++){
            ts.push_back(s[i]);
        }
        s=ts;
        ts.clear();

        cin>>a>>b;
        b=a+b;

        int idx=-1;
        for(int i=0;i<(int)s.size()-(int)b.size()+1;i++){
            for(int j=i;j<=i+b.size()-1;j++){
                if(s[j]!=b[j-i]) break;
                if(j==i+b.size()-1){
                    idx=i;
                }
            }
            if(idx!=-1) break;
        }

        if(idx==-1){
            s+=t;
            continue;
        }

        idx+=a.size();

        for(int i=0;i<idx;i++){
            ts.push_back(s[i]);
        }
        ts+=t;
        for(int i=idx;i<s.size();i++){
            ts.push_back(s[i]);
        }
        s=ts;
    }

    cout<<s;
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int ct=1;
    // cin>>ct;

    while(ct--){
        solve();
    }
}

7-7 分寝室

直接从 \(1\)\(n-1\) 循环一遍,女生分 \(i\) 间,男生分 \(n-i\)

对于每一个 \(i\),判断是否会出现单人寝室,判断是否可以平分。

对于所有合法的 \(i\),取一个男女差值最小的即可

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;

void solve(){
    int a,b,n;
    cin>>a>>b>>n;

    priority_queue<array<int,3>,vector<array<int,3>>,greater<array<int,3>>> q;
    for(int i=1;i<n;i++){
        if(a%i!=0 || b%(n-i)!=0) continue;
        if(a==i || b==(n-i)) continue;
        int x=a/i,y=b/(n-i);
        int diff=abs(x-y);
        q.push({diff,i,n-i});
    }

    if(q.size()){
        auto [diff,x,y]=q.top();
        cout<<x<<" "<<y;
    }
    else cout<<"No Solution";
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int ct=1;
    // cin>>ct;

    while(ct--){
        solve();
    }
}

7-8 谁管谁叫爹

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;

void solve(){
    int a,b,sa=0,sb=0;
    cin>>a>>b;
    int ta=a,tb=b;

    bool f1=0,f2=0;

    while(ta){
        sa+=ta%10;
        ta/=10;
    }
    
    while(tb){
        sb+=tb%10;
        tb/=10;
    }

    if(a%sb==0){
        f1=1;
    }
    if(b%sa==0){
        f2=1;
    }

    if(f1==f2){
        if(a>b) cout<<"A";
        else cout<<"B";
    }
    else if(f1) cout<<"A";
    else cout<<"B";

    cout<<endl;

}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int ct=1;
    cin>>ct;

    while(ct--){
        solve();
    }
}

7-9 堆宝塔

按照题意模拟即可

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;

void solve(){
    int n;
    cin>>n;

    int ans=0,mx=0;
    vector<int> a,b;
    
    while(n--){
        int val;
        cin>>val;

        if(a.size()==0 || val<a.back()) a.push_back(val);
        else if(b.size()==0 || val>b.back()) b.push_back(val);
        else{
            ans++;
            mx=max(mx,(int)a.size());
            a.clear();
            while(b.size() && b.back()>val){
                a.push_back(b.back());
                b.pop_back();
            } 
            a.push_back(val);
        }
    }

    if(a.size()){
        ans++;
        mx=max((int)a.size(),mx);
    }
    if(b.size()){
        ans++;
        mx=max((int)b.size(),mx);
    }

    cout<<ans<<" "<<mx;
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int ct=1;
    // cin>>ct;

    while(ct--){
        solve();
    }
}

7-10 天梯赛的赛场安排

依旧是小模拟,合理使用 STL 可以大幅简化代码

将每个学校按照 {剩余人数,学校} 的形式,存入优先队列中,每次去除剩余人数最多的学校

如果人数大于等于 \(n\),则需要新开一个考场,然后将剩余人数放回优先队列里

否则按照考场号从小到大,找一个剩余座位数量能放的下的考场,放进去,同时更新这个考场的剩余座位数。

否则新开一个考场,同时更新这个考场的剩余座位数。

点击查看代码
#include<bits/stdc++.h>
// #define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;

void solve(){
    int n,c,now=0;
    cin>>n>>c;

    vector<pair<string,int>> sc(n+1);
    priority_queue<pair<int,string>> q1;//{剩余人数,学校}
    vector<int> b(100001);

    map<string,int> mp;

    for(int i=1;i<=n;i++){
        cin>>sc[i].first>>sc[i].second;
        q1.push({sc[i].second,sc[i].first});
    }

    while(q1.size()){
        auto [cnt,name]=q1.top();
        q1.pop();
        mp[name]++;

        if(cnt>=c){
            cnt-=c;
            ++now;
            if(cnt!=0) q1.push({cnt,name});
        }
        else{
            bool f=0;
            for(int i=1;i<=now;i++){
                if(b[i]>=cnt){
                    b[i]-=cnt;
                    f=1;
                    break;
                }
            }
            if(f) continue;
            now++;
            b[now]=c-cnt;
        }
    }

    for(int i=1;i<=n;i++){
        cout<<sc[i].first<<" "<<mp[sc[i].first]<<endl;
    }
    cout<<now;


}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int ct=1;
    // cin>>ct;

    while(ct--){
        solve();
    }
}

7-11 锦标赛

\(cur\) 数组维护当前还剩余的空位,对于某一轮的第 \(j\) 比赛,胜者和败者一定是从 \(prel=cur[2*j-1]\)\(prel=cur[2*j]\) 中来的

现在需要做的是,给败者和胜者放进这两个空位中

限制条件是什么?

这两个空位,不管在当前轮次是胜者还是败者,它在之前的轮次,一定一直是胜者,需要击败很多人,可以用 \(limit\) 数组维护,每个位置之前击败的敌人数值的最大值。

如果要把败者放进 \(prer\),则需要满足败者的数值大于等于 \(limit[prer]\)\(prel\) 同理

所以要找一个满足条件的位置放进去,放进去后,另一个位置的限制条件需要用败者的数值更新。

如果某一次,两个位置都放不进去,则非法

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;

void solve(){
    int k;
    cin>>k;
    int n=1<<k;
    vector<int> a(n+1);
    vector rd(k+1,vector<int>());

    for(int i=1;i<=k;i++){
        int cnt=1<<(k-i);
        rd[i].push_back(0);
        for(int j=1;j<=cnt;j++){
            int val;
            cin>>val;
            rd[i].push_back(val);
        }
    }

    int win;
    cin>>win;

    vector<int> cur(n+1),limit(n+1);
    iota(cur.begin()+1,cur.end(),1);

    for(int i=1;i<=k;i++){
        vector<int> tmp;//下一轮的幸存者
        tmp.push_back(0);

        int cnt=rd[i].size()-1;//这一轮的比赛数
        for(int j=1;j<=cnt;j++){
            int loser=rd[i][j];
            int prel=cur[2*j-1];
            int prer=cur[2*j];

            if(loser>=limit[prel]){
                a[prel]=loser;
                limit[prer]=max(loser,limit[prer]);
                // limit[prer]=loser;
                tmp.push_back(prer);
            }
            else if(loser>=limit[prer]){
                a[prer]=loser;
                limit[prel]=max(loser,limit[prel]);
                // limit[prel]=loser;
                tmp.push_back(prel);
            }
            else{
                cout<<"No Solution";
                return;
            }
        }
        cur=tmp;
    }

    int pos=limit[1];
    if(win<limit[cur[1]]){
        cout<<"No Solution";
        return;
    }
    a[cur[1]]=win;

    cout<<a[1];
    for(int i=2;i<=n;i++){
        cout<<" "<<a[i];
    }
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int ct=1;
    // cin>>ct;

    while(ct--){
        solve();
    }
}

7-12 寻宝图

\(BFS\) 找到所有岛屿,对于每个岛屿,判断有没有宝藏即可

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;

int dx[]={-1,0,1,0};
int dy[]={0,1,0,-1};

void solve(){
    int n,m;
    cin>>n>>m;

    vector<vector<int>> g(n+1,vector<int>(m+1)),st(n+1,vector<int>(m+1));
    int cnt1=0,cnt2=0;
    
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            char ch;
            cin>>ch;
            g[i][j]=ch-'0';
        }
    }

    auto dfs2=[&](auto dfs2,int x,int y,int &mk)-> void {
        st[x][y]=1;
        if(g[x][y]>1 && mk==0){
            cnt2++;
            mk=1;
        }

        for(int i=0;i<4;i++){
            int a=x+dx[i],b=y+dy[i];
            if(a<1 || a>n || b<1 || b>m) continue;
            if(st[a][b] || g[a][b]==0) continue;

            dfs2(dfs2,a,b,mk);
        }
    };

    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(st[i][j] || g[i][j]==0) continue;
            cnt1++;
            int mk=0;
            dfs2(dfs2,i,j,mk);
        }
    }

    cout<<cnt1<<" "<<cnt2;

}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int ct=1;
    // cin>>ct;

    while(ct--){
        solve();
    }
}

7-14 完美树

天梯赛为数不多的好题,树形 DP

\(f[u] [0]\) 表示,以 \(u\) 为根节点的子树,使得所有节点中,\(0\)\(1\) 多一个的最小代价

\(f[u] [1]\) 表示,以 \(u\) 为根节点的子树,使得所有节点中,\(1\)\(0\) 多一个的最小代价

\(f[u] [2]\) 表示,以 \(u\) 为根节点的子树,使得所有节点中,\(1\)\(0\) 一样多的最小代价

显然,对于 \(sz[u]\) 为偶数的节点,只有 \(f[u] [0]\) 有意义。

对于对于 \(sz[u]\) 为奇数的节点,只有 \(f[u] [1]\)\(f[u] [2]\) 有意义。

计算完 \(u\) 的所有子节点 \(v\) 的值后,考虑如何计算 \(u\) 的值

首先对于 \(sz[v]\) 为偶数的点,只能使用 \(f[v] [2]\)

对于 \(sz[v]\) 为奇数的点,先全选 \(f[v] [1]\),并收集将每个 \(f[u] [1]\) 变成 \(f[u] [2]\) 的最小代价,使用尽可能小的代价,将一些 \(f[u] [1]\) 变成 \(f[u] [0]\)

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;

void solve(){
    int n;
    cin>>n;

    vector<vector<int>> g(n+1);
    vector<int> p(n+1),c(n+1);

    ////f[i][2]:一样多   f[i][1]:1比0多   f[i][0]:0比1多
    vector<array<int,3>> f(n+1,{inf,inf,inf});

    for(int u=1;u<=n;u++){
        int k;
        cin>>c[u]>>p[u]>>k;

        while(k--){
            int v;
            cin>>v;
            g[u].push_back(v);
        }
    }

    vector<int> sz(n+1);

    auto dfs=[&](auto dfs,int u)->void {
        sz[u]=1;
        if(g[u].size()==0){
            f[u][c[u]]=0;
            f[u][c[u]^1]=p[u];
            return;
        }

        int val=0;
        vector<int> tmp;

        for(auto v:g[u]){
            dfs(dfs,v);
            sz[u]+=sz[v];

            if(sz[v]%2==0){
                val+=f[v][2];
            }
            else{
                val+=f[v][1];
                tmp.push_back(f[v][1]-f[v][0]);//先假设所有奇子树都选1比0多
            }
        }

        if(c[u]==0){
            val+=p[u];
            tmp.push_back(p[u]);
        }
        else{
            tmp.push_back(-p[u]);
        }
        sort(tmp.begin(),tmp.end(),greater<int>());
        int k=tmp.size();

        if(sz[u]%2==0){  
            for(int i=0;i<k/2;i++){
                val-=tmp[i];
            }
            f[u][2]=val;
        }
        else{
            for(int i=0;i<k/2;i++){
                val-=tmp[i];
            }
            f[u][1]=val;
            val-=tmp[k/2];
            f[u][0]=val;
        }
    };

    dfs(dfs,1);

    cout<<min({f[1][0],f[1][1],f[1][2]});

}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int ct=1;
    // cin>>ct;

    while(ct--){
        solve();
    }
}
posted @ 2026-01-26 23:25  LYET  阅读(0)  评论(0)    收藏  举报