Order Capital Round 1 (Codeforces Round 1038, Div. 1 + Div. 2) A - D

A. Greedy Grid

点击查看代码
#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;
//using i128 = __int128_t;
const ll inf = 1e18;
const int mod = 998244353;

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

    if(n==1 || m==1 || (n==2 && m==2)){
        cout<<"NO\n";
    }
    else{
        cout<<"YES\n";
    }
}

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

    int ct=1;
    cin>>ct;
    while(ct--){
        solve();
    }
    return 0;
}

B. Pile Shuffling

因为题目保证一定有解,所有对于每一个堆,只需要考虑把多余的东西移出去即可。

如果某个堆缺少东西,则其他堆清理多余东西的时候就挪过来了

点击查看代码
#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;
//using i128 = __int128_t;
const ll inf = 1e18;
const int mod = 998244353;

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

    int ans=0;
    for(int i=1;i<=n;i++){
        int a,b,c,d;
        cin>>a>>b>>c>>d;

        ans+=max(0ll,a-c);
        ans+=max(0ll,b-d);
        if(b>d){
            ans+=min(a,c);
        }
    }
    cout<<ans<<endl;
}

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

    int ct=1;
    cin>>ct;
    while(ct--){
        solve();
    }
    return 0;
}

C. Manhattan Pairs

思路在代码注释里

点击查看代码
#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;
//using i128 = __int128_t;
const ll inf = 1e18;
const int mod = 998244353;

/*
答案对 X 和 Y 独立,要让答案最大,则要让 X 的答案和 Y 的答案都最大
对X:要让前n/2大的 X 和后n/2大的 X 一一结组
对Y:要让前n/2大的 Y 和后n/2大的 Y 一一结组
此时对X和对Y答案都最大
考虑有没有同时满足这两个条件的构造方式

先按照x,对点从小到到大排序,此时前一半x一定是较小的x
在分别对前一半点和后一半点,按照y从小到达排序即可
此时让(1,n), (2,n-1)....配对即为符合上述分析的解

x一定是符合的,因为是对全局排序的
y为什么也符合?前提:从小到大排序,数组左小右大
假设某次选中的两个点,y值都是前n/2,则左侧所有点都位于前n/2个
再加上选中的右侧的点,就有n/2+1个点位于前n/2
*/

struct node{
    int x,y,idx;
};

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

    vector<node> a(n+1);
    for(int i=1;i<=n;i++){
        cin>>a[i].x>>a[i].y;
        a[i].idx=i;
    }

    sort(a.begin()+1,a.end(),[&](node n1,node n2){
        return n1.x<n2.x;
    });

    sort(a.begin()+1,a.begin()+1+n/2,[&](node n1,node n2){
        return n1.y<n2.y;
    });

    sort(a.begin()+1,a.begin()+1+n/2,[&](node n1,node n2){
        return n1.y<n2.y;
    });

    sort(a.begin()+1+n/2,a.end(),[&](node n1,node n2){
        return n1.y<n2.y;
    });

    for(int i=1;i<=n/2;i++){
        cout<<a[i].idx<<" "<<a[n-i+1].idx<<endl;
    }
    
}

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

    int ct=1;
    cin>>ct;
    while(ct--){
        solve();
    }
    return 0;
}

D. Traffic Lights

可以证明,存在一条路径,满足从 1 移动到 n 的时间不超过 3*n

8e324f9c8de7b37b29374f5eea7a6796
证明来自: Max

所以只要暴力 DP t 从 1 到 3*n 的所有情况即可,一个类似与对 t 做分层图的东西

点击查看代码
#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;
//using i128 = __int128_t;
const ll inf = 1e18;
const int mod = 998244353;

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

    vector<vector<int>> g(n+1);
    while(m--){
        int u,v;
        cin>>u>>v;
        g[u].push_back(v);
        g[v].push_back(u);
    }

    //可以证明,最终的时间不会很大,<=3*n
    vector<int> f(n+1,inf);
    f[1]=0;

    int t=0;
    while(1){
        vector<int> tf(n+1,inf);
        for(int i=1;i<=n;i++){
            //当前第t秒时,在i处,枚举可以转移给谁
            tf[i]=min(tf[i],f[i]+1);
            int ne=g[i][(t)%g[i].size()];
            tf[ne]=min(tf[ne],f[i]);
        }
        f=move(tf);
        t++;
        if(f[n]!=inf){
            cout<<t<<" "<<f[n]<<endl;
            return;
        }
    }

}

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

    int ct=1;
    cin>>ct;
    while(ct--){
        solve();
    }
    return 0;
}
posted @ 2025-07-21 09:24  LYET  阅读(66)  评论(0)    收藏  举报