题解 | # 2026蓝桥杯B组省赛 #

满足,且,输出有多少个,那么就是
所以答案是


如果有一盏灯,总次数为
如果有两盏灯,总次数为         
如果有三盏灯,总次数为
如果有四盏灯,总次数为
手动模拟可以枚举到四盏灯,很显然一个结论是总次数等于 
打表代码:
#include<bits/stdc++.h>
using namespace std;

#define endl '\n'
#define int long long
#define debug(x) cout << #x << "= " << x << endl;
#define IOS ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define HelloWorld IOS;


void solve(){
    
    int n; cin >> n;
    vector<int> s(n);
    map<vector<int>, int> ma;
    ma[s] = 0;
    queue<vector<int> > q;
    q.push(s);
    while(q.size()){
        auto u = q.front();
        q.pop();
        for(int i = 0; i < (int)u.size(); i ++){
            auto v = u;
            if(ma[u] & 1){
                for(int j = 0; j <= i; j ++) v[j] ^= 1;
            }
            else{
                for(int j = i; j < n; j ++) v[j] ^= 1;
            }
            if(!ma.count(v)){
                ma[v] = ma[u] + 1;
                q.push(v);
            }
        }
    }
    int ans = 0;
    for(auto [v, w] : ma){
        for(int e : v) cout << e << " ";
        cout << endl;
        cout << "步数 = " << w << endl;
        ans += w;
    }
    cout << ans << endl;
    return ;
}

signed main(){
    HelloWorld;

    int tt = 1; 
    while(tt --) solve();
    return 0;
} 
右移一次后与原数组相同,所以就是,直接输出


需要满足两个条件就输出
  1. 总人数是的倍数
  2. 单个位置的人数不超过总战队数


对于的处理,一定是前面全部都是将设置为,后面全部将设置为,所以需要枚举分界点位置
一开始将全部的设置为,对于每个的位置用标记
然后从后向前枚举每一个位置,当然也可以从前向后枚举
考虑将一个换成的过程发生了什么,先记该位置为
  • 减少了该位置原来的[pos+1,n]这个区间里面的形成的LQ
  • 新增了中的与该位置现在的形成的LQ

总代码:
#include<bits/stdc++.h>
using namespace std;

#define endl '\n'
#define int long long
#define debug(x) cout << #x << "= " << x << endl;
#define IOS ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define HelloWorld IOS;


void solve(){

    int n; cin >> n;
    vector<char> a(n + 10);
    vector<int> vis(n + 10), pre(n + 10);
    for(int i = 1; i <= n; i ++){
        cin >> a[i];
        if(a[i] == '?'){
            vis[i] = true;
            a[i] = 'L';
        }
    }
    for(int i = 1; i <= n; i ++) pre[i] = pre[i - 1] + (a[i] == 'L');
    int ans = 0, now = 0, cnt = 0;
    for(int i = n; i >= 1; i --){
        if(a[i] == 'Q') cnt ++;
        else ans += cnt; 
    }
    now = ans, cnt = 0;
    for(int i = n; i >= 1; i --){
        if(vis[i]){
            now -= cnt;
            now += pre[i - 1];
            ans = max(ans, now);
            a[i] = 'Q';
        }
        if(a[i] == 'Q') cnt ++;
    }
    cout << ans << endl;
    return ;
}

signed main(){
    HelloWorld;

    int tt = 1; 
    while(tt --) solve();
    return 0;
}


求的第一个整数表示最少需要添加的应急跳线数量:其实连通块的数量减
求的第二个整数表示在确保跳线总数最少的前提下,单台计算机接入跳线数量最大值的最小可能值:注意看题,“接入这种应急跳线数量最多的那一台机器,其接入的跳线数降到最低”。
需要考虑的是连通块的大小(这个连通块里面的点的数量):
  • 如果数量大于等于,那么我可以选取两个不同的点接入应急跳线,此时这个连通块的最大值为
  • 如果数量等于,再如果这一个点可以只连接一条边,那么最大值为,否则最多只会连接两条边
设连通块大小为的数量为,大小大于等于的数量为
那么首先将大小大于等于的连通块连接起来:个连通块连接消耗了个点,个连通块连接消耗了个点,个连通块连接消耗了
那么其他的点都是一条边也没有连接的(设数量为),所以就可以给大小为的连通块连接。
所以如果,答案就是,否则为(一开始先判断答案是否为,即是不是一开始就是一个连通块)

总代码:
#include<bits/stdc++.h>
using namespace std;

#define endl '\n'
#define int long long
#define debug(x) cout << #x << "= " << x << endl;
#define IOS ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define HelloWorld IOS;


const int N = 100000 + 100;

int n, m, p[N], cnt[N];

int find(int x){
    if(x != p[x]) p[x] = find(p[x]);
    return p[x];
}

void solve(){

    cin >> n >> m;
    for(int i = 1; i <= n; i ++){
        p[i] = i;
        cnt[i] = 1;
    }
    for(int i = 1; i <= m; i ++){
        int u, v; cin >> u >> v;
        int fu = find(u), fv = find(v);
        if(fu != fv){
            cnt[fv] += cnt[fu];
            p[fu] = fv;
        }
    }
    int cnt1 = 0, cnt2 = 0, cnt3 = 0;
    for(int i = 1; i <= n; i ++){
        if(i == p[i]){
            if(cnt[i] == 1) cnt1 ++;
            else{
                cnt2 ++;
                cnt3 += cnt[i];
            }
        }
    }
    cout << (cnt1 + cnt2 - 1) << " ";
    if(cnt1 + cnt2 == 1) cout << 0 << endl;
    else{
        cnt3 -= 2 * (cnt2 - 1);
        if(cnt3 >= cnt1) cout << 1 << endl;
        else cout << 2 << endl;
    }
    return ;
}

signed main(){
    HelloWorld;

    int tt = 1; 
    while(tt --) solve();
    return 0;
}

显然只与数组和数组的差有关系,设
那么在一个区间上修改全部加上,如果,那么就表明满足题意,但是还得考虑一个东西就是如果这个区间里面一开始存在,那么加上后,,对答案的贡献就会减少
首先统计所有的个数设为,那么答案最少就为
然后考虑区间修改带来的影响:区间里面的数量减去区间里面等于的数量就是一个区间影响
  • 查询区间的个数可以用前缀和
  • 一个很重要的贪心是区间上修改时,一定满足,这样可以满足数量最大的同时减少等于的数量
所以可以想到将每个数出现的位置存下来,用存储
那么在里面,对于来讲:
的个数为个,它们对应的位置为,那么的个数为,所以区间的贡献为,分离变量为(j-pre[v[j]]+1)-(i-pre[v[i]])
那么我们就可以直接依次遍历里面的每一个数,然后当前的就是,同时维护的最小值

总代码:
#include<bits/stdc++.h>
using namespace std;

#define endl '\n'
#define int long long
#define debug(x) cout << #x << "= " << x << endl;
#define IOS ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define HelloWorld IOS;

void solve(){
    int n; cin >> n;
    vector<int> a(n + 10), b(n + 10), c(n + 10), pre(n + 10);
    int cnt = 0;
    map<int, vector<int> > ma;
    for(int i = 1; i <= n; i ++) cin >> a[i];
    for(int i = 1; i <= n; i ++){
        cin >> b[i];
        c[i] = b[i] - a[i];
        pre[i] = pre[i - 1] + (c[i] == 0);
        if(c[i] == 0) cnt ++;
        else ma[c[i]].push_back(i);
    }    
    int ans = cnt, now = 0;
    for(auto [x, v] : ma){
        now = 1;
        if((int)v.size() > 1){
            int MIN = 0 - pre[v[0]];
            for(int i = 1; i < (int)v.size(); i ++){
                now = max(now, (i - pre[v[i]]) - MIN + 1);
                MIN = min(MIN, i - pre[v[i]]);
            }
        }
        ans = max(ans, cnt + now);
    }
    cout << ans << endl;
    return ;
}

signed main(){
    HelloWorld;

    int tt = 1; 
    while(tt --) solve();
    return 0;
}


给了个球员的初始能力,以及每训练一天增加的能力,那么如果给第个球员天的训练时间,则他的能力变为。一共有天的训练时间,要求所有的球员训练时间之和为,即,求的最大值

,其中\prod_{i=1}^{n}{b_{i}}为常数,所以只与有关
对于的取值,贪心的是优先选择小的,因为:例如),如果给最小的加上,那么总值就会加上,而是最大的那三个数,所以优先选择最小的那个数可以使得总乘积最大

那么是满足单调性的,即只会增加不会减少,对于次增加值,可以用浮点数二分找到的值:
首先对于增加到假设要次,那么,所以,用函数,然后对取最大值
int cnt = 100;
double l = 0, r = 2e14, pos = 0;
while(cnt --){
    double mid = (l + r) / 2.0;
    if(check(mid)){
        pos = mid;
        l = mid;
    }
    else r = mid;
}
因为浮点数二分直接循环次就可以了
如果总次数比说明取大了,寻找更小值
否则说明还可以取更大值,寻找更大值
bool check(double x){
    int cnt = 0;
    for(int i = 1; i <= n; i ++){
        double v = (double)a[i] / (double)b[i];
        int cur = (int)ceil(x - v);
        cur = max(0LL, cur);
        cnt += cur;
        if(cnt > m) return false;
    }
    return true;
}
那么现在得到后,然后对每一个进行操作
 priority_queue<Node , vector<Node>, cmp> q;
for(int i = 1; i <= n; i ++){
    double v = (double)a[i] / (double)b[i];
    int cur = (int)ceil(pos - v);
    cur = max(0LL, cur);
    a[i] += cur * b[i];
    m -= cur;
    q.push({a[i], b[i], i});
}
  • 为了让已经用了很多了,可以保证,因为如果,则可以直接让所有的都在加上一个值,这样就不是最大的了
  • 用优先队列模拟剩下最小的的情况;同时需要记录下标,因为最终答案需要用到

总代码:
#include<bits/stdc++.h>
using namespace std;

#define endl '\n'
#define int long long
#define debug(x) cout << #x << "= " << x << endl;
#define IOS ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define HelloWorld IOS;


const int N = 100000 + 100;
const int mod = 998244353;

int n, m;
int a[N], b[N];

bool check(double x){
    int cnt = 0;
    for(int i = 1; i <= n; i ++){
        double v = (double)a[i] / (double)b[i];
        int now_cnt = ceil(x - v);
        now_cnt = max(0LL, now_cnt);
        cnt += now_cnt;
        if(cnt > m) return false;
    }
    return true;
}

struct Node{
    double x, y, id;
};

struct cmp{
    bool operator() (const Node &a, const Node &b) const{
        return a.x * b.y > a.y * b.x;
    }
};

void solve(){
    
    cin >> n >> m;
    for(int i = 1; i <= n; i ++) cin >> a[i] >> b[i];

    int cnt = 100;
    double l = 0, r = 2e14, pos = 0;
    while(cnt --){
        double mid = (l + r) / 2;
        if(check(mid)){
            pos = mid;
            l = mid;
        }
        else r = mid;
    }

    priority_queue<Node, vector<Node>, cmp> q;
    for(int i = 1; i <= n; i ++){
        double v = (double)a[i] / (double)b[i];
        int now_cnt = ceil(pos - v);
        now_cnt = max(0LL, now_cnt);
        a[i] += now_cnt * b[i];
        m -= now_cnt;
        q.push({a[i], b[i], i});
    }
    while(m --){
        int x = q.top().x;
        int y = q.top().y;
        int id = q.top().id;
        a[id] += y;
        q.pop();
        q.push({a[id], y, id});
    }

    int ans = 1;
    for(int i = 1; i <= n; i ++){
        a[i] %= mod;
        ans = (ans * a[i]) % mod;
    }
    cout << ans << endl;
    return ;
}

signed main(){
    HelloWorld;

    int tt = 1; 
    while(tt --) solve();
    return 0;
}
全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务