题解 | # 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;
}
右移一次后与原数组相同,所以就是
,直接输出
需要满足两个条件就输出
-
总人数是
的倍数
- 单个位置的人数不超过总战队数
对于
的处理,一定是前面全部都是将
设置为
,后面全部将
设置为
,所以需要
枚举分界点位置
一开始将全部的
设置为
,对于每个
的位置用
标记
然后从后向前枚举每一个位置,当然也可以从前向后枚举
考虑将一个
从
换成
的过程发生了什么,先记该位置为
-
减少了该位置原来的
与
这个区间里面的
形成的
-
新增了
中的
与该位置现在的
形成的
总代码:
#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;
}
显然只与
数组和
数组的差有关系,设
那么在一个区间上修改全部加上
,如果
,那么就表明
满足题意,但是还得考虑一个东西就是如果这个区间里面一开始存在
,那么加上
后,
,对答案的贡献就会减少
首先统计所有
的个数设为
,那么答案最少就为
然后考虑区间修改带来的影响:区间里面的
数量减去区间里面
等于
的数量就是一个区间影响
-
查询区间
的个数可以用前缀和
-
一个很重要的贪心是区间上修改时,一定满足
,这样可以满足
数量最大的同时减少
等于
的数量
所以可以想到将每个数出现的位置存下来,用
存储
那么在
里面,对于
来讲:
那么我们就可以直接依次遍历
里面的每一个数,然后当前的就是
,同时维护
的最小值
总代码:
#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;
}
给了
个球员的初始能力
,以及每训练一天增加的能力
,那么如果给第
个球员
天的训练时间,则他的能力变为
。一共有
天的训练时间,要求所有的球员训练时间之和为
,即
,求
的最大值
对于
的取值,贪心的是优先选择
小的,因为:例如
(
),如果给最小的
加上
,那么总值就会加上
,而
是最大的那三个数,所以优先选择最小的那个数可以使得总乘积最大
设
那么
是满足单调性的,即
只会增加不会减少,对于
次增加值,可以用浮点数二分找到
的值:
首先对于
增加到
假设要
次,那么
,所以
,用
函数,然后对
取最大值
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;
}
查看11道真题和解析