Codeforces Round 983 (Div. 2)

A

最坏的情况就是所有开着的开关尽可能配对

最好的情况就是所有开着的开关尽可能不配对

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int>PII;
const int N=1e6+10;
const int mod=998244353;
const int INF  = 0x3f3f3f3f;
const ll INFll  = 0x3f3f3f3f3f3f3f3f;
#define endl "\n" 

//vector<vector<int>>adj(N);


void solve()
{
    int n; cin >> n;
    int sum = 0;
    for(int i = 1; i <= 2 * n; i ++) {
        int x; cin >> x;
        sum += x;
    }
    cout << sum%2 << " ";
    if(sum > n) sum -= 2 * (sum - n);
    cout << sum << endl;
}


signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    cout << setprecision(11) << fixed;
    int t;t=1;
    cin>>t;
    for(int i=1;i<=t;i++){
        //printf("Case %d: ",i);
        solve();
    }
}

B

分析

首先要保证 k 这个数作为 k 所在区间的中位数,那么就直接让这个区间以 k 为中心,

k 在第一轮被选出来后,要使得第二轮的中位数也为 k ,那么左边区间数量应该等于右边区间数量
直接使这个左右区间数量为1

现在就只有三个区间,"左","中", "右".

只剩一个要求了,所有区间的长度为奇数,第一轮构造可以保证 |中| 是奇数.

又因为题目保证 n 为奇数,我们枚举 |中|, 直接计算左右两个区间的长度,找到三个区间长度都为奇数的情况.

实际上 奇 = 偶 + 奇 + 偶 或者 奇 = 奇 + 奇 + 奇,

这两种情况会交替出现,加上边界判断,可以让这个枚举的复杂度降到 o(1)

n = 1 时不可能有3个区间,要特判

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int>PII;
const int N=1e6+10;
const int mod=998244353;
const int INF  = 0x3f3f3f3f;
const ll INFll  = 0x3f3f3f3f3f3f3f3f;
#define endl "\n" 

//vector<vector<int>>adj(N);


void solve()
{
    int n, k;
    cin >> n >> k;
    int len = 0;
    if(n == 1) {
        cout << 1 << endl;
        cout << 1 << endl;
        return;
    }
    while(1) {
        if(k - len < 1 || k + len > n) break;
        int l = k - 1 - len ;
        int r = n - k - len;
        // cout << l << " " << r << endl;
        if(l%2 && r%2) {
            cout << 3 << endl;
            cout << 1 << " " << l + 1 << " " << n - r + 1 << endl;
            return;
        }
        len ++;
    }

    cout << "-1" << endl;

}


signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    cout << setprecision(11) << fixed;
    int t;t=1;
    cin>>t;
    for(int i=1;i<=t;i++){
        //printf("Case %d: ",i);
        solve();
    }
}

C

分析

题目要求任选三个数都可以组成非退化三角形,所以最后所有数的取值都一个离散区间内,这个区间的要求是+>
那么在这个区间任选 3 个数,都可以组成三角形
所有将所有数排序,枚举所有数做区间最小值时,最大值可以取到多少,不在这个区间内的数个数就是需要的操作次数。
如何求右端点呢,显然可以二分,
这里提供一个双指针做法,因为随着最小值增大,最大值必然不减

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int>PII;
const int N=1e6+10;
const int mod=998244353;
const int INF  = 0x3f3f3f3f;
const ll INFll  = 0x3f3f3f3f3f3f3f3f;
#define endl "\n" 

//vector<vector<int>>adj(N);


void solve()
{
    int n; cin >> n;
    vector<int> a(n);
    for(int i = 0; i < n; i ++) cin >> a[i];
    sort(a.begin(), a.end());
    int ans = 0;
    int r = 0;
    for(int l = 0; l < n - 1; l ++) { // 区间为[l,r)
        while(r < n && a[l] + a[l + 1] > a[r]) r ++;
        ans = max(r - l, ans);
    }
    cout << n - ans << endl;
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    cout << setprecision(11) << fixed;
    int t;t=1;
    cin>>t;
    for(int i=1;i<=t;i++){
        //printf("Case %d: ",i);
        solve();
    }
}

D

分析

题目明确表明去掉 0 点的图就是多条链

同时 1 号点是第一条链的第一个点

根据 x<=y=>px<=py 这个条件,可以确定图的序号大致排布方式如下图

接下来就很好办了,所有点从小到大枚举,首先通过 1 在确定第一层(直接连接 0)有多少点

从第二层开始,每次判断当前这个点是否挂在这个上一层某个点下方,
根据父节点不减和每个父节点最多一个儿子两个条件
用双指针优化这个操作

代码中
因为每次只涉及到相邻2层的关系, 用了个类似dp中滚动数组的方式开了2个数组

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int>PII;
const int N=1e6+10;
const int mod=998244353;
const int INF  = 0x3f3f3f3f;
const ll INFll  = 0x3f3f3f3f3f3f3f3f;

//vector<vector<int>>adj(N);

int ask(int a, int b) {
    int ans;
    cout << "? " << a << " " << b << endl;
    cin >> ans;
    return ans;
}


void solve()
{
    int n;
    cin >> n;
    vector<int>p(n, 0);
    vector<int>fa,fa2;
    p[1] = 0;
    int i;
    for(i = 2; i < n; i ++) {
        if(ask(1, i) == 0) {
            p[i] = 1;
            fa.push_back(i);
            i ++;
            break;
        } 
        p[i] = 0;
        fa.push_back(i);
    }
    int j = 0;
    for(; i < n ; i ++) {
        while(j < (int)fa.size() && ask(fa[j], i) == 1) {
            j ++;
        }
        if(j >= (int)fa.size()) {
            swap(fa, fa2);
            fa2.clear();
            i --; // 注意这个地方,因为上一层点用完了才停了下来,并不是找到了p[i]
            j = 0;
        } else {
            p[i] = fa[j]; 
            fa2.push_back(i);
            j ++;
        }
    }

    cout << "! ";
    for(int i = 1; i < n; i ++) cout << p[i] << " "; cout << endl; 
}


signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    cout << setprecision(11) << fixed;
    int t;t=1;
    cin>>t;
    for(int i=1;i<=t;i++){
        //printf("Case %d: ",i);
        solve();
    }
}

posted @   Haborym  阅读(76)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
点击右上角即可分享
微信分享提示