Contest2897 - 2023寒假集训-进阶训练赛(一)

问题 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的莲花上。

你将进行如下操作若干次:

  1. 选定任意的2个正整数A, B,初始分数为0。假设当前位置为x:
  2. 你的坐标移动到 x + A 这个位置上 , 并且y = x + A 
    • 如果y=N−1,游戏结束。
    • 如果y≠N−1,但是y这个莲花存在,那么分数增加si,并且这片莲花消失。
    • 如果y≠N−1,但是y这个莲花不存在,那么分数减去10的100次方,游戏结束。
  3. 你的坐标移动到 x - B 这个位置上 , 并且y = x - B
    • 如果y=N−1,游戏结束。
    • 如果y≠N−1,但是y这个莲花存在,那么分数增加si,并且这片莲花消失。
    • 如果y≠N−1,但是y这个莲花不存在,那么分数减去10的100次方,游戏结束。
  4. 然后不断重复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;
}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值