【CodeForces训练记录】Codeforces Round 1006 (Div. 3)

训练情况

赛后反思

结束前打表看出来了 F 有一点进制的规律,太极限了来不及写了

A题

显然不合法的情况就是所有元素绝对值的和都比和的绝对值小,这种情况无论怎么凑都到不了 \(k\),剩下的就是把和均摊到值域上,除以值域向上取整就是答案

点击查看代码
#include <bits/stdc++.h>
// #define int long long
#define endl '\n'

using namespace std;

void solve(){
    int n,k,p; cin>>n>>k>>p;
    if(abs(n*p)<abs(k)) cout<<-1<<endl;
    else cout<<abs(ceil(1.0*abs(k)/abs(p)))<<endl;
}

signed main(){
    int T; cin>>T; while(T--)
    solve();
    return 0;
}

B题

简单的高中组合数学,我们显然发现 -_- 下划线放在中间,横杠放在两边,子序列个数为三部分的个数乘积,我们想要答案最大,根据均值不等式显然得对半分放在两侧,奇数偶数分类讨论即可

点击查看代码
#include <bits/stdc++.h>
#define int long long
#define endl '\n'

using namespace std;

void solve(){
    int n; cin>>n;
    string s; cin>>s;
    int cnt1 = 0,cnt2 = 0;
    for(int i = 0;i<n;i++){
        if(s[i] == '-') cnt1++;
        else if(s[i] == '_') cnt2++;
    }
    if(cnt1&1){
        int x = cnt1/2;
        cout<<x*(x+1)*cnt2<<endl;
    } else {
        int x = cnt1/2;
        cout<<x*x*cnt2<<endl;
    }
}

signed main(){
    int T; cin>>T; while(T--)
    solve();
    return 0;
}

C题

我们考虑从 0 开始到 n 枚举每一位是否可以放,因为按位或要等于 k,所以 k 的 0 位置不能出现 1,筛掉不合法的数,之后先将能放的数扔到答案数组里,如果不够 n 的话,直接补 x,按位或还是不变,如果超过 n 的话,会导致高位无法达到 x 的高位,按位或会不等于 x,这时候我们直接修改最后一位即可

点击查看代码
#include <bits/stdc++.h>
#define int long long
#define endl '\n'

using namespace std;

void solve(){
    vector<int> ans;
    int n,x; cin>>n>>x;
    vector<bool> vis(n + 1,1);
    for(int i = 0;i<n;i++){
        for(int j = 32;~j;j--){
            if(((i>>j)&1)&& (((x>>j)&1) == 0)) vis[i] = 0;
        }
    }
    for(int i = 0;i<n;i++){
        if(vis[i]) ans.emplace_back(i);
    }
    while(ans.size() < n) ans.emplace_back(x);
    int o = 0;
    for(int i = 0;i<n;i++) o |= ans[i];
    if(o!=x) ans[n-1] = x;
    for(int i = 0;i<n;i++) cout<<ans[i]<<" ";
    cout<<endl;
}

signed main(){
    int T; cin>>T; while(T--)
    solve();
    return 0;
}

D题

显然区间左移我们可以等效看成最左边的数扔到区间最右边,对于操作区间 \([l,r]\),无论如何操作 l 左边的逆序对贡献不变,r 右边的逆序对贡献不变,贡献变的只是区间 \([l,r]\) 逆序对减少的个数,我们直接 \(O(n^2)\) 求大于当前位的数的个数和小于当前位的数的个数,贡献就是小-大,答案取大值更新 \(l,r\) 即可

点击查看代码
#include <bits/stdc++.h>
// #define int long long
#define endl '\n'

using namespace std;


void solve(){
    int n; cin>>n;
    vector<int> a(n + 1);
    vector<int> sm(n + 1),bi(n + 1);
    for(int i = 1;i<=n;i++) cin>>a[i];
    int now = 0;
    int l = 1,r = 1;
    for(int i = 1;i<=n;i++){
        int cnt = 0;
        for(int j = i+1;j<=n;j++){
            if(a[j] < a[i]) sm[i]++;
            else if(a[j] > a[i]) bi[i]++;
            if(sm[i]-bi[i] > now){
                now = sm[i] - bi[i];
                l = i;
                r = j;
            }
        }
    }
    cout<<l<<" "<<r<<endl;
}

signed main(){
    int T; cin>>T; while(T--)
    solve();
    return 0;
}

E题

显然题目的公式可以推出来在直角三角形里 \(a+b=c,a^2+b^2=c^2\),代入后发现 \(ab = 0\),所以一定两人同在某一行或某一列答案才有贡献,因为求的是对数,我们考虑放在同一行,每增加一个人的贡献是一个首项 1,公差 1 的等差数列,题目人数又有限制,所以我们尽量放在一行让数列和尽可能接近 n,如果仍然不足跳到下一行,以此类推

点击查看代码
#include <bits/stdc++.h>
#define int long long
#define endl '\n'

using namespace std;

const int N = 1e9;

void solve(){
    int n; cin>>n;
    vector<pair<int,int>> ans;
    int tot = 0,now = 0;
    while(n){
        ++now;
        int pos = 1;
        int sum = 0;
        while(sum+pos<=n){
            sum += pos;
            pos++;
        }
        for(int i = 1;i<=pos;i++) ans.push_back({now,i+tot});
        tot += pos;
        n-=sum;
    }
    cout<<ans.size()<<endl;
    for(int i = 0;i<ans.size();i++){
        cout<<ans[i].first<<" "<<ans[i].second<<endl;
    }
}

signed main(){
    int T; cin>>T; while(T--)
    solve();
    return 0;
}
posted @   MNNUACM_2024ZY  阅读(279)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示