问题 A: 校门外的树
题目描述
某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米。我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置;数轴上的每个整数点,即0,1,2,……,L,都种有一棵树。
由于马路上有一些区域要用来建地铁。这些区域用它们在数轴上的起始点和终止点表示。已知任一区域的起始点和终止点的坐标都是整数,区域之间可能有重合的部分。现在要把这些区域中的树(包括区域端点处的两棵树)移走。你的任务是计算将这些树都移走后,马路上还有多少棵树。
输入
第一行有两个整数L(1 ≤ L ≤ 10000)和 M(1 ≤ M ≤ 100),L代表马路的长度,M代表区域的数目,L和M之间用一个空格隔开。接下来的M行每行包含两个不同的整数,用一个空格隔开,表示一个区域的起始点和终止点的坐标。
对于20%的数据,区域之间没有重合的部分;对于其它的数据,区域之间有重合的情况。
输出
包括一行,这一行只包含一个整数,表示马路上剩余的树的数目。
样例输入
500 3
150 300
100 200
470 471
样例输出
298
AC代码
//区间合并
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int>PII;
int L, M;
vector<PII>v1, v2;
int main() {
cin >> L >> M;
while (M--) {
int l, r;
cin >> l >> r;
v1.push_back({ l,r });
}
sort(v1.begin(), v1.end());
int l = v1[0].first, r = v1[0].second;
for (auto item : v1) {
if (item.first <= r) {
if (item.second > r)r = item.second;
}
else {
v2.push_back({ l,r });
l = item.first, r = item.second;
}
}
v2.push_back({ l,r });
int cnt = 0;
for (auto item : v2) {
cnt += item.second - item.first + 1;
}
cout << L + 1 - cnt << endl;
return 0;
}
问题 B: 开关灯
题目描述
假设有N盏灯(N为不大于5000的正整数),从1到N按顺序依次编号,初始时全部处于开启状态;有M个人(M为不大于N的正整数)也从1到M依次编号。
第一个人(1号)将灯全部关闭,第二个人(2号)将编号为2的倍数的灯打开,第三个人(3号)将编号为3的倍数的灯做相反处理(即将打开的灯关闭,将关闭的灯打开)。依照编号递增顺序,以后的人都和3号一样,将凡是自己编号倍数的灯做相反处理。
请问:当第M个人操作之后,哪几盏灯是关闭的,按从小到大输出其编号,其间用逗号间隔。
输入
输入正整数N和M,以单个空格隔开。
输出
顺次输出关闭的灯的编号,其间用逗号间隔。
样例输入
10 10
样例输出
1,4,9
AC代码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int n = 5e3 + 10;
int N, M;
int a[n];
int main() {
cin >> N >> M;
for (int i = 2; i <= M; i++) {
for (int j = i; j <= N; j += i) {
a[j] = (a[j] == 0) ? 1 : 0;
}
}
cout << 1;
for (int i = 2; i <= N; i++) {
if (a[i] == 0)cout << "," << i;
}
return 0;
}
问题 C: 配对碱基链
题目描述
脱氧核糖核酸(DNA)由两条互补的碱基链以双螺旋的方式结合而成。而构成DNA的碱基共有4种,分别为腺瞟呤(A)、鸟嘌呤(G)、胸腺嘧啶(T)和胞嘧啶(C)。我们知道,在两条互补碱基链的对应位置上,腺瞟呤总是和胸腺嘧啶配对,鸟嘌呤总是和胞嘧啶配对。你的任务就是根据一条单链上的碱基序列,给出对应的互补链上的碱基序列。
输入
一个字符串,表示一条碱基链。这个字符串只含有大写字母A、T、G、C,分别表示腺瞟呤、胸腺嘧啶、鸟嘌呤和胞嘧啶。字符串长度不超过255。
输出
一个只含有大写字母A、T、G、C的字符串,为与输入的碱基链互补的碱基链。
样例输入
ATATGGATGGTGTTTGGCTCTG
样例输出
TATACCTACCACAAACCGAGAC
AC代码
#include<bits/stdc++.h>
using namespace std;
string s;
int main() {
cin >> s;
for (auto item : s) {
if (item == 'A' || item == 'T') {
cout << ((item == 'A') ? 'T' : 'A');
}
else cout << ((item == 'C') ? 'G' : 'C');
}
return 0;
}
问题 D: 矩阵交换行
题目描述
给定一个5×5的矩阵(数学上,一个r×c的矩阵是一个由r行c列元素排列成的矩形阵列),将第n行和第m行交换,输出交换后的结果。
输入
输入共6行,前5行为矩阵的每一行元素,元素与元素之间以一个空格分开。
第6行包含两个整数m、n,以一个空格分开(1≤m,n≤5)。
输出
输出交换之后的矩阵,矩阵的每一行元素占一行,元素之间以一个空格分开。
样例输入
1 2 2 1 2
5 6 7 8 3
9 3 0 5 3
7 2 1 4 6
3 0 8 2 4
1 5
样例输出
3 0 8 2 4
5 6 7 8 3
9 3 0 5 3
7 2 1 4 6
1 2 2 1 2
AC代码
#include<bits/stdc++.h>
using namespace std;
int a[6][6];
int m, n;
int main() {
for (int i = 1; i <= 5; i++) {
for (int j = 1; j <= 5; j++) {
cin >> a[i][j];
}
}
cin >> m >> n;
for (int i = 1; i <= 5; i++) {
for (int j = 1; j <= 5; j++) {
if (i == m || i == n) {
cout << a[((i == m) ? n : m)][j] << " ";
}
else cout << a[i][j] << " ";
}
cout << endl;
}
return 0;
}
问题 E: 【蓝桥杯2022初赛】统计子矩阵
题目描述
给定一个 N × M 的矩阵A,请你统计有多少个子矩阵(最小 1 × 1,最大 N × M) 满足:
子矩阵中所有数的和不超过给定的整数K?
输入
第一行包含三个整数N, M 和K.
之后 N 行每行包含 M 个整数,代表矩阵A.
30%的测试数据:1≤N,M≤20;
70%的测试数据:1≤N,M≤100;
100%的测试数据:1≤N,M≤500;0≤Aij≤1000;1≤K≤250000000。
输出
答案
样例输入
3 4 10
1 2 3 4
5 6 7 8
9 10 11 12
样例输出
19
AC代码
//前缀和、双指针
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int n = 510;
int N, M, K;
int a[n][n];
LL res = 0;
int main() {
cin >> N >> M >> K;
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= M; j++) {
cin >> a[i][j];
a[i][j] += a[i - 1][j];
}
}
for (int x1 = 1; x1 <= N; x1++) {
for (int x2 = x1; x2 <= N; x2++) {
for (int l = 1, r = 1, sum = 0; r <= M; r++) {
sum += a[x2][r] - a[x1 - 1][r];
while (sum > K) {
sum -= a[x2][l] - a[x1 - 1][l];
l++;
}
res += r - l + 1;
}
}
}
cout << res << endl;
return 0;
}
问题 F: 【蓝桥杯2022初赛】修建灌木
题目描述
爱丽丝要完成一项修剪灌木的工作。
有 N 棵灌木整齐的从左到右排成一排。
爱丽丝在每天傍晚会修剪一棵灌木,让灌木的高度变为 0 厘米。
爱丽丝修剪灌木的顺序是从最左侧的灌木开始,每天向右修剪一棵灌木。
当修剪了最右侧的灌木后,她会调转方向,下一天开始向左修剪灌木。
直到修剪了最左的灌木后再次调转方向。然后如此循环往复。
灌木每天从早上到傍晚会长高 1 厘米,而其余时间不会长高。
在第一天的早晨,所有灌木的高度都是 0 厘米。爱丽丝想知道每棵灌木最高长到多高。
输入
一个正整数N ,含义如题面所述。
30%的测试数据:1<N≤10;
100%的测试数据:1<N≤10000。
输出
输出 N 行,每行一个整数,第 i 行表示从左到右第 i 棵树最高能长到多高。
样例输入
3
样例输出
4
2
4
AC代码
#include<bits/stdc++.h>
using namespace std;
int N;
int main() {
cin >> N;
for (int i = 1; i <= N; i++) {
cout << max(N - i, i - 1) * 2 << endl;
}
return 0;
}
问题 G: 求和
题目描述
小T给你两个整数K和S,问你有多少个不同的三元组(X, Y, Z)满足:
X+Y+Z=S
0≤X,Y,Z≤K
输入
一行空格隔开的两个整数K和S,其中
2≤K≤2500
0≤S≤3K
输出
满足条件的三元组的个数
样例输入
2 2
样例输出
6
AC代码
#include<bits/stdc++.h>
using namespace std;
int K, S;
int res = 0;
int X, Y, Z;
int main() {
cin >> K >> S;
for (X = 0; X <= K; X++) {
for (Y = 0; Y <= K; Y++) {
Z = S - X - Y;
if (0 <= Z && Z <= K)res++;
}
}
cout << res << endl;
return 0;
}
问题 H: 不论你距我多远,哪怕刀山火海我愿为你走天下
题目描述
小T和她的男神位于一个二维坐标平面上,x和y轴的正方向分别是水平向右和竖直向上。小T位于点(sx, sy),男神位于点(tx, ty),满足男神在小T的右上方。小T到每次可以向上或向下或向左或向右移动一个单位,她要到他的身旁(tx, ty),再回到她自己原来的位置(sx, sy),再回到他的身旁(tx, ty),再回到自己原来的位置(sx, sy)。
请输出一种最短的走法,满足:除了(sx, sy)和(tx, ty)外,不经过同一个点两次。
输入
一行用空格隔开的4个整数sx, sy, tx, ty (-1000≤sx, sy, tx, ty≤1000)
代表小T的起始位置(sx, sy)和男神的位置(tx, ty)
输出
输出一种小T的合法路径,分别用UDLR来代表每一步的上下左右,具体可见样例及解释
请按样例的方式来走QAQ
样例输入
0 0 1 2
样例输出
UURDDLLUUURRDRDDDLLU
AC代码
#include<bits/stdc++.h>
using namespace std;
int sx, sy, tx, ty;
int dx, dy;
int main() {
cin >> sx >> sy >> tx >> ty;
dx = tx - sx, dy = ty - sy;
for (int i = 0; i < dy; i++)cout << "U";
for (int i = 0; i < dx; i++)cout << "R";
for (int i = 0; i < dy; i++)cout << "D";
for (int i = 0; i < dx + 1; i++)cout << "L";
for (int i = 0; i < dy + 1; i++)cout << "U";
for (int i = 0; i < dx + 1; i++)cout << "R";
cout << "DR";
for (int i = 0; i < dy + 1; i++)cout << "D";
for (int i = 0; i < dx + 1; i++)cout << "L";
cout << "U" << endl;
return 0;
}
问题 I: 跑图
题目描述
给你一个N点M边的无向带权连通简单图(无向、带权、连通、无自环、无重边)
其中第i(1≤i≤M)条边连接点ai和bi,权重是ci
输出不属于任意两点的最短路径的边的条数。
输入
2≤N≤100
N-1≤M≤min(N(N-1)/2,1000)
1≤ai,bi≤N
1≤ci≤1000
ci是整数
给定的图没有自环也没有重边
给定的图是连通图
输入的格式是:
N M
a1 b1 c1
a2 b2 c2
...
am bm cm
输出
输出不属于任意两点的最短路径的边的条数。
即:如果点a和点b的最短路径经过了边c,那么c不是答案中的一条。
样例输入
3 3
1 2 1
1 3 1
2 3 3
样例输出
1
AC代码
#include <bits/stdc++.h>
using namespace std;
#define cctie \
ios::sync_with_stdio(0); \
cin.tie(0); \
cout.tie(0);
#define int long long
#define PII pair<int, int>
#define fr first
#define sc second
#define all(x) x.begin(), x.end()
const int N = 110, M = 2010;
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int c)
{
e[++idx] = b, ne[idx] = h[a], h[a] = idx, w[idx] = c;
}
int n, m;
bool ex[N][N];
int d[N];
bool st[N];
int fa[N];
void dijkstra(int u)
{
memset(fa, 0, sizeof fa);
memset(st, 0, sizeof st);
memset(d, 0x3f, sizeof d);
d[u] = 0;
priority_queue<PII, vector<PII>, greater<PII>> pq;
pq.push({0, u});
while (!pq.empty())
{
auto t = pq.top();
pq.pop();
int dist = t.first, ver = t.second;
if (st[ver])
continue;
st[ver] = true;
for (int i = h[ver]; i != -1; i = ne[i])
{
int j = e[i];
if (d[j] > dist + w[i])
{
d[j] = dist + w[i];
pq.push({d[j], j});
fa[j] = ver;
}
}
}
for (int i = 1; i <= n; i++)
if (fa[i])
ex[fa[i]][i] = true;
}
void solve()
{
cin >> n >> m;
memset(h, -1, sizeof h);
for (int i = 1; i <= m; i++)
{
int a, b, c;
cin >> a >> b >> c;
add(a, b, c);
add(b, a, c);
}
for (int i = 1; i <= n; i++)
dijkstra(i);
int ans = m;
for (int i = 1; i <= n; i++)
{
for (int j = i + 1; j <= n; j++)
if (ex[i][j] || ex[j][i])
ans--;
}
cout << ans << '\n';
}
signed main()
{
cctie;
int T = 1;
// cin >> T;
while (T--)
solve();
return 0;
}
问题 J: Ensemble’s heritage
题目描述
作为十三课的卢卡,是没有权力去直接审讯犯人的。所以卢卡就偷到了N张卡,监狱一共有M个房间。第i个监狱的门可以由 第L,L+1,L+2, ... ,R张卡打开。
但是卢卡的数学并不好,他想让你帮帮他,有几张卡能打开所有的门。
输入
N M
L1 R1
L2 R2
L3 R3
...
LN RN
1≤N,M≤1e5
1≤Li≤Ri≤N
输出
一个整数,代表答案
样例输入
4 2
1 3
2 4
样例输出
2
AC代码
#include<bits/stdc++.h>
using namespace std;
int N, M;
int l = INT_MIN, r = INT_MAX;
int main() {
cin >> N >> M;
while (M--) {
int L, R;
cin >> L >> R;
l = max(l, L), r = min(r, R);
}
if (l <= r)cout << r - l + 1 << endl;
else cout << 0 << endl;
return 0;
}
问题 K: 珠宝
题目描述
你的朋友送了你一个序列D,这个序列D上一共有n个珠宝,按照从左到右的顺序,每个珠宝都有它的价值w[i]。
1 <= n <= 50
-1e7 <= w[i] <= 1e7
你可以对这些珠宝进行最多k次操作。
1 <= k <= 100
每次操作你都可以操作A:取出D中最左边的宝石,放在手中。当D为空时,不能执行此操作。
操作B:取出D中最右边的宝石,放在手中。当D为空时,不能执行此操作。
操作C:选择手中的任意一个宝石并将其插入D的左端。如果手中没有宝石,则无法执行此操作。
操作D:选择手中的任意一个宝石并将其插入D的右端。如果手中没有宝石,则无法执行此操作。
求执行完 最多k次操作之后 你手上有的珠宝的价值之和的最大值。
输入
n k
w1 w2 ...... wn
输出
执行完最多k次操作之后你手上有的珠宝的价值之和的最大值
样例输入
6 4
-10 8 2 1 2 6
样例输出
14
AC代码
#include<bits/stdc++.h>
using namespace std;
int n, k;
int a[100];
int res = 0;
int main() {
cin >> n >> k;
for (int i = 1; i <= n; i++)cin >> a[i];
for (int i = 0; i <= min(n, k); i++) {
for (int j = 0; j <= min(n, k) - i; j++) {
vector<int>v;
int t = k - (i + j), cnt = 0;
for (int l = 1; l <= i; l++) {
v.push_back(a[l]);
}
for (int l = n; l >= n - j + 1; l--) {
v.push_back(a[l]);
}
sort(v.begin(), v.end());
while (t-- && !v.empty() && v[0] < 0) {
v.erase(v.begin());
}
for (auto item : v) {
cnt += item;
}
res = max(res, cnt);
}
}
cout << res << endl;
return 0;
}
问题 L: 道路工程
题目描述
有一条从西到东的无限长的街道,我们认为这是一条无限长的数轴
这条街上计划进行N项道路工程。
第i个道路工程在坐标Xi处阻段该点 阻挡的时间从Si - 0.5 到 Ti - 0.5
也就是说在 Si - 0.5 到 Ti - 0.5 这段时间内 Xi 这个点不能通过
第i个人将在时间Di开始从坐标0 , 不断以速度1个单位每秒正向行走,到达阻段点时停止行走。
求出每个人将要走的距离
如果这个人走的过程中不会遇到阻断点
则输出-1
1 <= N , Q <= 2e5 (200000)
0 <= Si < Ti <= 1e9 (1000000000)
1 <= Xi <= 1e9
0 <= D1 < D2 < D3 < ....... < Dq <= 1e9
输入
N Q
S1 T1 X1
S2 T2 X2
...........
Sn Tn Xn
D1
D2
.....
Dq
输出
每行一个数
输出第i个人将要走的距离
如果这个人走的过程中不会遇到阻断点
则输出-1
样例输入
4 6
1 3 2
7 13 10
18 20 13
3 4 2
0
1
2
3
5
8
样例输出
2
2
10
-1
13
-1
AC代码
#include<bits/stdc++.h>
using namespace std;
typedef struct ban {
double S, T, X;
}ban;
typedef pair<double, int> PDI;
const int N = 2e5 + 10;
int n, q, ans[N];
ban b[N];
set<PDI> s;
set<PDI>::iterator it;
bool cmp(ban b1, ban b2) {
return b1.X < b2.X;
}
int main() {
cin >> n >> q;
memset(ans, -1, sizeof ans);
for (int i = 1; i <= n; i++) {
double S, T, X;
cin >> S >> T >> X;
b[i] = { S - 0.5 - X, T - 0.5 - X, X };
}
sort(b + 1, b + 1 + n, cmp);
for (int i = 1; i <= q; i++) {
double D;
cin >> D;
s.insert({ D, i });
}
for (int i = 1; i <= n; i++) {
while (!s.empty()) {
it = s.lower_bound({ b[i].S, 0 });
if (it == s.end() || it->first > b[i].T) break;
ans[it->second] = b[i].X;
s.erase(it);
}
}
for (int i = 1; i <= q; i++) cout << ans[i] << endl;
return 0;
}
问题 M: 蛙跳
题目描述
小T在第七共和国的中心大楼发生了爆炸之后重生了,他发现他现在是一只青蛙,如果要重新变回人类,他需要解决这道问题
有无限广阔的池塘,可以看作是一条直线。
这个池塘里漂浮着n个莲花,它们的坐标为0,1,.....n-1.。你在最初坐标0的莲花上。
你将进行如下操作若干次:
- 选定任意的2个正整数A, B,初始分数为0。假设当前位置为x:
- 你的坐标移动到 x + A 这个位置上 , 并且y = x + A
- 如果y=N−1,游戏结束。
- 如果y≠N−1,但是y这个莲花存在,那么分数增加si,并且这片莲花消失。
- 如果y≠N−1,但是y这个莲花不存在,那么分数减去10的100次方,游戏结束。
- 你的坐标移动到 x - B 这个位置上 , 并且y = x - B
- 如果y=N−1,游戏结束。
- 如果y≠N−1,但是y这个莲花存在,那么分数增加si,并且这片莲花消失。
- 如果y≠N−1,但是y这个莲花不存在,那么分数减去10的100次方,游戏结束。
- 然后不断重复2 3操作
问你如何选择A,B 可以让最后的得分最大,输出该得分。
输入
n
s0 s1 ...... sn-1
1 <= n <= 1e5
-1e9 <= si <= 1e9
s0 = sn−1 = 0
输出
问选定最优的A、B的情况下,得到的最高分数为多少?
样例输入
5
0 2 5 1 0
样例输出
3
AC代码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e5 + 10;
int n, s[N], f[N];
LL ans;
int main() {
cin >> n;
for (int i = 0; i < n; i++) cin >> s[i];
for (int C = 1; C < n - 1; C++) {
LL cnt = 0;
for (int K = 1; K * C < n - 1; K++) {
int a = n - 1 - K * C, b = K * C;
int A = a, B = A - C;
if (B <= 0 || a == b || f[a] == C || f[b] == C) break;
cnt += s[a] + s[b];
f[a] = f[b] = C;
ans = max(ans, cnt);
}
}
cout << ans << endl;
return 0;
}