Codeforces Round 1023 (Div. 2) A - F1

A. LRC and VIP

把最大值分一组,其他值分一组即可。

如果整个数组一样,那就是NO。

点击查看代码
#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 mx=0;
    int idx=0;

    vector<int> a(n+10);

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

    for(int i=1;i<=n;i++){
        if(a[i]!=mx) break;
        if(i==n){
            cout<<"No\n";
            return;
        }
    }

    cout<<"Yes\n";

    for(int i=1;i<=n;i++){
        if(i!=idx) cout<<1<<" ";
        else cout<<2<<" ";
    }

    cout<<endl;


}   

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

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

    return 0; 
}

B. Apples in Boxes

奇奇妙妙博弈题

在特判条件上卡了半小时,真不应该

最大值mx,最小值mn。

如果 mx - mn 的值 > k+1 ,则第一个人必输。

如果 mx - mn 的值 == k+1 ,且有多个mx值,则第一个人必输,因为就算让一个mx-1,也有其他mx让第一个人输。

否则就是一个奇偶博弈。

点击查看代码
#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,k;
    cin>>n>>k;
    int sum=0;

    vector<int> a(n+1);

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

    int mx=*max_element(a.begin()+1,a.end());
    int mn=*min_element(a.begin()+1,a.end());

    int cnt=0;

    for(int i=1;i<=n;i++){
        if(a[i]==mx) cnt++;
    }

    if(mx-mn>k+1){
        cout<<"Jerry"<<endl;
        return;
    }

    if(mx-mn==k+1 && cnt>1){
        cout<<"Jerry"<<endl;
        return;
    }

    if(sum&1){
        cout<<"Tom";
    }else{
        cout<<"Jerry";
    }

    cout<<endl;
} 

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

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

    return 0; 
}

C. Maximum Subarray Sum

赛时想复杂了,其实很简单一题,最后几分钟多写了一个错误的判断条件,wa了。

首先先把所有缺失的地方赋值成 -inf.

跑一边dp,对每个被-inf分割的块计算最大子数组和。令最大值为 t

如果t>k,则无解

如果t==k,则直接输出数组即可

如果t<k,则随便找一个-inf,位置是pos,把这个-inf和改成某个值,使得t=k即可。

如何计算改成的值?

需要知道:

从前往后算以每个位置的为结尾的最大子数组和dp[i]

从后往前算以每个位置的为结尾的最大子数组和idp[i]

这个值 == k- ( max(0, dp[i-1]) + max(0,idp[i+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;
//using i128 = __int128_t;
const ll inf = 100'000'000'000'000'000;
const int mod = 998244353;

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

    string s;
    cin>>s;
    s=" "+s;

    int ans=0;

    vector<int> a(n+10),dp(n+10),f(n+10),idp(n+10);

    for(int i=1;i<=n;i++){
        cin>>a[i];
        if(s[i]=='1') f[i]=1;
        if(f[i]==0) a[i]=-inf;
    }


    for(int i=1;i<=n;i++){
        dp[i]=a[i];
        dp[i]=max(dp[i],a[i]+dp[i-1]);
        ans=max(ans,dp[i]);
    }

    if(ans>k){
        cout<<"No\n";
        return;
    }
    else if(ans==k){
        cout<<"Yes\n";
        for(int i=1;i<=n;i++){
            cout<<a[i]<<" ";
        }
        cout<<endl;
        return;
    }

    //ans<k

    for(int i=n;i>=1;i--){
        idp[i]=a[i];
        idp[i]=max(idp[i],a[i]+idp[i+1]);
    }


    for(int i=1;i<=n;i++){
        if(f[i]==1) continue;
        int t1=max(0ll,dp[i-1]);
        int t2=max(0ll,idp[i+1]);

        a[i]=k-(t1+t2);

        cout<<"Yes\n";
        for(int j=1;j<=n;j++){
            cout<<a[j]<<" ";
        }
        cout<<endl;
        return;
    }
    cout<<"No\n";

}   

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

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

    return 0; 
}

D. Apple Tree Traversing

显然是找树的直径 -> 删直径 -> 找直径 循环。

复杂度是n*sqrtn

找到一条直径并删除后,剩下的节点被分为很多个不联通的块,分治每个块即可。

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

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

    vector<vector<int>> g(n+1);

    for(int i=1;i<n;i++){
        int u,v;
        cin>>u>>v;
        g[u].push_back(v);
        g[v].push_back(u);
    }

    vector<int> vis(n+1);
    vector<array<int,3>> ans;

    vector<int> fa(n+1),dep(n+1);

    auto work=[&](auto work,int now)->void {
        
        
        vector<int> a;//以now为根节点,能走到的节点

        auto dfs=[&](auto dfs,int u,int pre)->void {
            dep[u]=dep[pre]+1;
            fa[u]=pre;
            a.push_back(u);

            for(auto v:g[u]){
                if(vis[v] || v==pre) continue;
                dfs(dfs,v,u);
            }
        };

        dfs(dfs,now,0);

        int rt1=0,rt2=0;

        for(auto u:a){
            if(dep[u]>dep[rt1]) rt1=u;
            else if(dep[u]==dep[rt1]) rt1=max(rt1,u);
        }

        dfs(dfs,rt1,0);

        for(auto u:a){
            if(dep[u]>dep[rt2]) rt2=u;
            else if(dep[u]==dep[rt2]) rt2=max(rt2,u);
        }

        int cnt=0, tmp=rt2;

        while(tmp!=0){
            vis[tmp]=1;
            cnt++;
            tmp=fa[tmp];
        }

        ans.push_back({cnt, max(rt1,rt2),min(rt1,rt2)});

        for(auto u:a){
            if(vis[u]) continue;
            work(work,u);
        }
    };

    work(work,1);

    sort(ans.begin(),ans.end(),greater<>());

    for(auto [a,b,c]:ans){
        cout<<a<<" "<<b<<" "<<c<<" ";
    }
    cout<<endl;

}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    
    int ct=1;
    cin>>ct;

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

E. Ain and Apple Tree

学的洛谷题解第一篇

就这种构造题赛时见到包做不出来

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

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

    vector<int> a;

    for(int i=n-1;i>=1;i--){
        int val=i*(i-1)/2;
        if(k>=val){
            k-=val;
            a.push_back(i);
        }
    }

    if(k>1){
        cout<<"No\n";
        return;
    }

    cout<<"Yes\n";

    int now=1,cnt=1,sum=n;
    for(auto val:a){
        for(int i=1;i<=sum-val;i++){
            cout<<now<<" "<<++cnt<<endl;
        }
        sum=val;
        now=cnt;
    }
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    
    int ct=1;
    cin>>ct;

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

F1. Cycling (Easy Version)

范围是5000,考虑n^2的dp

设f[i]表示从i后面跳到0的最小代价,初始f[0]=0;

对每个i,枚举j:(0,i-1),表示从i后面跳到j后面,再跳到0

每次跳跃,用区间(j+1,i)内的最小值跳到j后面

设最小值val的位置pos,则f[i]=min: f[j]+i-pos+val*(i-j)+i-j-1

i-pos: 把val从pos换到位置i的代价

val*(i-j): 每次跨过val的代价

i-j-1: 每次把val往前交换一次的代价

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

/*
设f[i]表示从i后面跳到0的最小代价,初始f[0]=0;

对每个i,枚举j:(0,i-1),表示从i后面跳到j后面,再跳到0

每次跳跃,用区间(j+1,i)内的最小值跳到j后面

设最小值val的位置pos,则f[i]=min: f[j]+i-pos+val*(i-j)+i-j-1

i-pos: 把val从pos换到位置i的代价
val*(i-j): 每次跨过val的代价
i-j-1: 每次把val往前交换一次的代价
*/

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

    vector<int> a(n+10,inf),f(n+10,inf);

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

    for(int i=1;i<=n;i++){
        int val=inf,pos=0;

        for(int j=i-1;j>=0;j--){
            if(a[j+1]<val){
                pos=j+1;
                val=a[j+1];
            }

            f[i]=min(f[i],f[j]+i-pos+val*(i-j)+i-j-1);
        }
    }
    
    cout<<f[n]<<endl;
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    
    int ct=1;
    cin>>ct;

    while(ct--){
        solve();
    }
    return 0;
}
posted @ 2025-05-06 20:50  LYET  阅读(81)  评论(0)    收藏  举报