蓝桥杯C++大学B组一个月冲刺记录2024/3/3
规则:每日三题
1.递增三元组
给定三个整数数组
A=[A1,A2,…AN]
B=[B1,B2,…BN]
C=[C1,C2,…CN]
请你统计有多少个三元组 (i,j,k)
满足:
1≤i,j,k≤N
Ai<Bj<Ck
二分
最容易想到的是将三个数组sort排序,然后用二分去分别查找小于和大于的下标。然后相乘累加进答案。但是为什么没有AC捏?
1.忽略了二分查找未找到的情况,例如第三个数组中若没有比T更大的数,那么返回的下标是N,而不是N+1。有两个方法解决(1)如我下方做法一样,加入if判断。让 l ++ 或者 l – (2)在第一个数组的第一个元素加入一个极小数,在第二个数组的最后一个元素加入一个极大数。然后扩大l r 的范围
2.**findminer(p[2][j]) * (N - findmaxer(p[2][j]) + 1)**爆int了,转化为long long
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int M = 1e5+10;
int p[4][M];
int N;
typedef long long LL;
int findminer(int T){
int l = 1,r = N;
while(l < r){
int mid = (l + r + 1)/2;
if(p[1][mid] >= T) r = mid - 1;
else l = mid;
}
if(p[1][l] >= T) l --;
return l;
}
int findmaxer(int T){
int l = 1,r = N;
while(l < r){
int mid = (l + r)/2;
if(p[3][mid] <= T) l = mid + 1;
else r = mid;
}
if(p[3][l] <= T) l ++;
return l;
}
int main(){
cin >> N;
for(int i = 1;i <= 3; ++i){
for(int j = 1;j <= N; ++j){
cin >> p[i][j];
}
sort(p[i] + 1,p[i] + N + 1);
}
long long int ans = 0;
for(int j = 1;j <= N;++j){
ans += (LL)findminer(p[2][j]) * (N - findmaxer(p[2][j]) + 1);
}
cout << ans << endl;
return 0;
}
2.壁画
壁画题目全是bihua,就不贴了
前缀和
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
const int M = 5e6+10;
int res[M];
int T;
int main(){
cin >> T;
for(int i = 1;i <= T;++i){
int n;
string str;
cin >> n;
cin >> str;
for(int j = 0;j < n; ++ j){
res[j + 1] = str[j] - '0';
res[j + 1] += res[j];
}
int m = (n + 1) / 2;
int ans = -1;
for(int j = m;j <= n;++j){
ans = max(ans,res[j] - res[j-m]);
}
printf("Case #%d: %d\n", i, ans);
}
}
3.棋盘
小蓝拥有 n×n大小的棋盘,一开始棋盘上全都是白子。
小蓝进行了 m次操作,每次操作会将棋盘上某个范围内的所有棋子的颜色取反(也就是白色棋子变为黑色,黑色棋子变为白色)。
请输出所有操作做完后棋盘上每个棋子的颜色。
二维差分
#include<iostream>
#include<cstdio>
using namespace std;
const int M = 2005;
int b[M][M];
int n,T;
void insert(int x1,int y1,int x2,int y2){
b[x1][y1] += 1;
b[x2 + 1][y1] -= 1;
b[x1][y2 + 1] -= 1;
b[x2 + 1][y2 + 1] += 1;
}
int main(){
cin >> n >> T;
while(T--){
int x1,y1,x2,y2;
cin >> x1 >> y1 >> x2 >> y2;
insert(x1,y1,x2,y2);
}
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= n; j ++ )
b[i][j] += b[i - 1][j] + b[i][j - 1] - b[i - 1][j - 1];
for (int i = 1; i <= n; i ++ )
{
for (int j = 1; j <= n; j ++ ) printf("%d", b[i][j]%2);
puts("");
}
return 0;
}
4.重新排序
给定一个数组 A和一些查询 Li,Ri,求数组中第 Li 至第 Ri个元素之和。小蓝觉得这个问题很无聊,于是他想重新排列一下数组,使得最终每个查询结果的和尽可能地大。
小蓝想知道相比原数组,所有查询结果的总和最多可以增加多少?
差分
总和大的关键在于让较大的数字数字被更多的查询
所以用差分数组去记录各个下标被查询的次数,然后将差分数组和原数组重新排序,相乘相加。确保较大的数得到较大的查询的次数
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
const int M = 1e5+10;
int res[M],pos[M];
int n,T;
LL sum1,sum2;
int main(){
cin >> n;
for(int i = 1;i <= n; ++i){
cin >> pos[i];
}
cin >> T;
while(T--){
int l,r;
cin >> l >> r;
res[l] += 1;
res[r + 1] -= 1;
}
for(int i = 1;i <= n;++i){
res[i] += res[i-1];
sum1 += (LL)res[i] * pos[i];
}
sort(res + 1,res + n + 1);
sort(pos + 1,pos + n + 1);
for(int i = 1;i<=n;++i){
sum2 += (LL)res[i] * pos[i];
}
cout << sum2 - sum1 << endl;
return 0;
}
5.差分
输入一个长度为 n的整数序列。接下来输入 m个操作,每个操作包含三个整数 l,r,c,表示将序列中 [l,r] 之间的每个数加上 c。
请你输出进行完所有操作后的序列。
一维差分
#include<cstdio>
#include<iostream>
using namespace std;
const int M = 1e5+10;
int res[M],pos[M];
int n,T;
int main(){
cin >> n >> T;
for(int i = 1;i <= n; ++i){
cin >> pos[i];
res[i] = pos[i] - pos[i-1];
}
while(T--){
int l,r,k;
cin >> l >> r >> k;
res[l] += k;
res[r+1] -= k;
}
for(int i = 1;i <= n;++i){
res[i] += res[i - 1];
cout << res[i] << ' ';
}
return 0;
}
6.差分矩阵
输入一个 n行 m列的整数矩阵,再输入 q个操作,每个操作包含五个整数 x1,y1,x2,y2,c,其中 (x1,y1)和 (x2,y2)表示一个子矩阵的左上角坐标和右下角坐标。
每个操作都要将选中的子矩阵中的每个元素的值加上 c。
请你将进行完所有操作后的矩阵输出。
二维差分
#include<iostream>
#include<cstdio>
using namespace std;
const int M = 1010;
int p[M][M];
int res[M][M];
int n,m,T;
void insert(int x1,int y1,int x2,int y2, int c){
res[x1][y1] += c;
res[x2+1][y1] -= c;
res[x1][y2+1] -= c;
res[x2+1][y2+1] += c;
}
int main(){
cin >> n >> m >> T;
for(int i = 1;i<=n;++i){
for(int j = 1;j<=m;++j){
cin >> p[i][j];
insert(i,j,i,j,p[i][j]);
}
}
while(T--){
int x1,y1,x2,y2,c;
cin >> x1 >> y1 >> x2 >> y2 >> c;
insert(x1,y1,x2,y2,c);
}
for(int i = 1;i <= n;++i){
for(int j = 1;j <= m;++j){
res[i][j] += res[i-1][j] + res[i][j-1] - res[i-1][j-1];
cout << res[i][j] << ' ';
}
cout << endl;
}
return 0;
}