华北理工大学·第五届ACM秋季校赛题面&&标程
华北理工大学·第五届ACM秋季校赛题面&&标程
比赛题目跳转:华北理工大学·第五届ACM秋季校赛
A.ACMer进击蓝桥
题目描述

第十五届蓝桥杯全国软件和信息技术专业人才大赛(以下简称蓝桥杯大赛)正在紧张的报名中,大赛赛项中的软件赛包含的C/C++程序设计,Java软件开发和Python程序设计和此次校赛的包含的算法知识点内容几乎一致,只是校赛对应的ACM赛制和蓝桥杯对应的OI赛制不同,两者区别在哪呢,如下描述所示:
ACM赛制:每道题提交之后都有反馈,可以看到“通过”、“运行错误”、“答案错误”等等结果,但看不到错误的测试样例(leetcode周赛可以看到),每道题都有多个测试点,每道题必须通过了所有的测试点才算通过。每道题不限制提交次数,但没通过的话会有罚时,仅以最后一次提交为准,未正确解答的试题不记时。比赛过程中一般可以看到实时排名,通过题数相同的情况下按照答题时间+罚时来排名。
OI赛制:每道题提交之后都没有任何反馈,每道题都有多个测试点,根据每道题通过的测试点的数量获得相应的分数。每道题不限制提交次数,如果提交错误没有任何惩罚,仅以最后一次提交为准。比赛过程中看不到实时排名,赛后按照总得分来排名。
通过以上海报和描述,你可以很清楚的了解到比赛的报名和蓝桥杯大赛与此次校赛的赛制区别,所以你积极报名了2024年的蓝桥杯大赛,为了进一步了解OI赛制,你通过网络进一步检索信息, 进行深入的了解,突然你发现了一道关于OI的题目:
在一张白色背景的图像上,有一些黑色的字符,小唐发现这些字符可以分为两类:不包含任何洞的OI中的“I”,含一个洞的OI中的“O”。现在,用“.”表示白色背景,用“#”表示背景上的黑色字迹,小唐想问问你,这两类字符各有多少个?
你现在非常有兴趣解决这道题目,给出你的设计程序。
输入
第一行两个整数,n($ 1 \leqslant n \leqslant 1000 $)和 $ m(1 \leqslant m \leqslant 1000) $。
随后\(n\)行,每行\(m\)个字符, 表示该黑白图像。
输出
输出一行两个整数,分别表示“O”的个数,“I”的个数。
样例输入1
4 11 #.###.##### #.#.#.#...# #.#.#.#...# #.###.#####
样例输出1
2 1
样例输入2
3 6 ####.# ##.#.# ####.#
样例输出2
1 1
注意
题目保证图像不会存在含有多个洞的字符,并且保证字符之间互不嵌套或者重叠,字符的各个洞的位置不重叠,字符的每个“#”之间四连通。
标程
- C 版本
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#define N 1010
char s[N][N];
int st[N][N];
int vis[N][N];
int n, m;
int dxy[][2] = {0, -1, 0, 1, 1, 0, -1, 0, -1, 1, -1, -1, 1, -1, 1, 1};
bool bfs0(int sx, int sy)
{
struct { int x, y; } q[100000000];
bool flag = true;
int hh = 0, tt = 0;
st[sx][sy] = true;
q[0].x = sx;
q[0].y = sy;
while (hh <= tt)
{
int x = q[hh].x, y = q[hh++].y;
if (x == n - 1 || y == m - 1 || x == 0 || y == 0) flag = false;
for (int i = 0; i < 8; i++)
{
int nx = x + dxy[i][0];
int ny = y + dxy[i][1];
if (nx >= n || ny >= m || nx < 0 || ny < 0) continue;
if (st[nx][ny] || s[nx][ny] == '#') continue;
st[nx][ny] = true;
q[++tt].x = nx;
q[tt].y = ny;
}
}
return flag;
}
void bfs1(int sx, int sy)
{
struct { int x, y; } q[100000000];
int hh = 0, tt = 0;
q[0].x = sx;
q[0].y = sy;
vis[sx][sy] = true;
while (hh <= tt)
{
int x = q[hh].x, y = q[hh++].y;
for (int i = 0; i < 4; i++)
{
int nx = x + dxy[i][0];
int ny = y + dxy[i][1];
if (nx >= n || ny >= m || nx < 0 || ny < 0) continue;
if (vis[nx][ny] || s[nx][ny] == '.') continue;
vis[nx][ny] = true;
q[++tt].x = nx;
q[tt].y = ny;
}
}
}
void solve()
{
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i++)
scanf("%s", s[i]);
int cnt0 = 0, cnt1 = 0;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
if (!st[i][j] && s[i][j] == '.')
if (bfs0(i, j)) cnt0++;
if (!vis[i][j] && s[i][j] == '#')
bfs1(i, j), cnt1++;
}
}
printf("%d %d\n", cnt0, cnt1 - cnt0);
}
int main()
{
int t = 1;
while (t--)
solve();
return 0;
}
- C++ 版本
#include<bits/stdc++.h>
using namespace std;
const int N = 1e4 + 10;
string s[N];
bool st[N][N];
bool vis[N][N];
int n, m;
int dxy[][2] = {0, -1, 0, 1, 1, 0, -1, 0, -1, 1, -1, - 1, 1, -1, 1, 1};
bool bfs0(int sx, int sy)
{
bool flag = true;
queue<pair<int,int> > q;
q.push({sx, sy});
st[sx][sy] = true;
while(q.size())
{
auto t = q.front();
int x = t.first;
int y = t.second;
if(x == n - 1 || y == m - 1 || x == 0 || y == 0) flag = false;
q.pop();
for(int i = 0; i < 8; i++)
{
int nx = x + dxy[i][0];
int ny = y + dxy[i][1];
if(nx >= n || ny >= m || nx < 0 || ny < 0) continue;
if(st[nx][ny] || s[nx][ny] == '#') continue;
st[nx][ny] = true;
q.push({nx, ny});
}
}
return flag;
}
void bfs1(int sx, int sy)
{
queue<pair<int,int> > q;
q.push({sx, sy});
vis[sx][sy] = true;
while(q.size())
{
auto t = q.front();
int x = t.first;
int y = t.second;
q.pop();
for(int i = 0; i < 4; i++)
{
int nx = x + dxy[i][0];
int ny = y + dxy[i][1];
if(nx >= n || ny >= m || nx < 0 || ny < 0) continue;
if(vis[nx][ny] || s[nx][ny] == '.') continue;
vis[nx][ny] = true;
q.push({nx, ny});
}
}
}
void solve()
{
cin >> n >> m;
for(int i = 0; i < n; i++)
cin >> s[i];
int cnt0 = 0, cnt1 = 0;
for(int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
if (!st[i][j] && s[i][j] == '.')
if (bfs0(i, j)) cnt0++;
if (!vis[i][j] && s[i][j] == '#')
bfs1(i, j), cnt1++;
}
}
cout << cnt0 << " " << cnt1 - cnt0 << "\n";
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1;
while(t--)
solve();
return 0;
}
- python版本
import sys
from collections import deque
N = 1010
sys.setrecursionlimit(100000)
s = [""] * N
st = [[False] * N for _ in range(N)]
vis = [[False] * N for _ in range(N)]
dxy = [(0, -1), (0, 1), (1, 0), (-1, 0), (1, 1), (1, -1), (-1, -1), (-1, 1)]
def bfs0(sx, sy, n, m):
flag = True
q = deque([(sx, sy)])
st[sx][sy] = True
while q:
x, y = q.popleft()
if x == n - 1 or y == m - 1 or x == 0 or y == 0:
flag = False
for i in range(8):
nx, ny = x + dxy[i][0], y + dxy[i][1]
if nx >= n or ny >= m or nx < 0 or ny < 0:
continue
if st[nx][ny] or s[nx][ny] == "#":
continue
st[nx][ny] = True
q.append((nx, ny))
return flag
def bfs1(sx, sy, n, m):
q = deque([(sx, sy)])
vis[sx][sy] = True
while q:
x, y = q.popleft()
for i in range(4):
nx, ny = x + dxy[i][0], y + dxy[i][1]
if nx >= n or ny >= m or nx < 0 or ny < 0:
continue
if vis[nx][ny] or s[nx][ny] == ".":
continue
vis[nx][ny] = True
q.append((nx, ny))
def solve():
n, m = map(int, input().split())
for i in range(n):
s[i] = input()
cnt0, cnt1 = 0, 0
for i in range(n):
for j in range(m):
if not st[i][j] and s[i][j] == ".":
if bfs0(i, j, n, m):
cnt0 += 1
if not vis[i][j] and s[i][j] == "#":
bfs1(i, j, n, m)
cnt1 += 1
print(cnt0, cnt1 - cnt0)
t = 1
for _ in range(t):
solve()
B. Baidu的池塘规划
题目描述

2023年8月28日至9月4日,第35届国际信息学奥林匹克竞赛(IOI 2023)在匈牙利顺利举行, 令人激动的是,中国队四位选手经过不懈努力,最终全员夺金,包揽冠亚军,并成功夺得团体第一名!他们为国争光,载誉归来,而这四位选手,都是“百度之星”!他们都是曾经百度程序设计大赛中的佼佼者,就在今年四月,在由教育部批准、中国高等教育学会主办的中国高等教育博览会上,“ 百度之星”被正式纳入“国赛”名单,成为高校教育教学改革和创新人才培养的重要竞赛项目。
大赛中也诞生过“开挂”的天才高中生,他在自己的ACM生涯早期中遇到过一些曾经困扰他的题目,尽管这些问题已经被克服,但为了考验你的编程水平,他把印象深刻的一道题目描述给你,期待你用卓越的编程能力去解决,题意如下:
假设有一个矩形池塘,长为 A 米,宽为 B 米。现在想要养一些青蛙和鱼类,由于鱼类通常会吃掉小型的青蛙(蝌蚪)或者它们的卵,所以必须要在这个池塘内部安置一个正三角形的网将两类生物分隔开,现在需要你设计这个正三角形的网,使得该正三角形的占的面积尽可能大, 除此之外,由于池塘的主人偏爱青蛙,需要把青蛙安置到面积较大的区域内,需要你作出规划。
输入
两个整数A和B(\(A,B\leqslant 10^5\)),分别表示池塘的长和宽。
输出
输出两行。
第一行,输出最大正三角形的边长,输出与真实答案的绝对误差或相对误差均不超过\(10^{-6}\),则认为你的输出是正确答案。
第二行,输出正三角形安置的生物,如果是青蛙,请输出“Frog”, 否则输出“Fish”
样例输入
1 1
样例输出
1.03527618041008295791 Fish
注意
样例的池塘如下所示,其最大边长为\(\sqrt{6} - \sqrt{2}\),三角形面积为0.464102,其余部分的面积为0.535898,所以最终的三角形内安置的生物为鱼类。

请注意,样例输出结果和正解答案误差在 \(10^{-6 }\)范围内,因此被视为正确答案。
标程
- C 版本
#include<stdio.h>
#include<math.h>
#define PI acos(-1)
double f(double x, double y)
{
return (x / cos(y / 180.0 * PI));
}
void solve()
{
double a, b;
scanf("%lf %lf", &a, &b);
if(a > b)
{
int t = a;
a = b;
b = t;
}
double l = 0.0, r = 30.0;
while(fabs(r - l) > 1e-10)
{
double mid = (l + r) / 2.0;
if(f(a, mid) < f(b, 30 - mid)) l = mid;
else r = mid;
}
double n = f(a, l);
double area = n * n * sqrt(3) / 4.0;
double rest = a * b - area;
int res = area * 1000000;
int ans = rest * 1000000;
printf("%.10lf\n", n);
if(res > ans) printf("Frog\n");
else printf("Fish\n");
}
int main()
{
int t = 1;
while(t--)
solve();
return 0;
}
- C++ 版本
#include<bits/stdc++.h>
#define PI acos(-1)
using namespace std;
double f(double x, double y)
{
return (x / cos(y / 180.0 * PI));
}
void solve()
{
double a, b;
cin >> a >> b;
if(a > b) swap(a, b);
double l = 0.0, r = 30.0;
while(fabs(r - l) > 1e-10)
{
double mid = (l + r) / 2.0;
if(f(a, mid) < f(b, 30 - mid)) l = mid;
else r = mid;
}
double n = f(a, l);
double area = n * n * sqrt(3) / 4.0;
double rest = a * b - area;
long long res = area * 1000000;
long long ans = rest * 1000000;
cout << fixed << setprecision(10) << n << "\n";
if(res > ans) cout << "Frog\n";
else cout << "Fish\n";
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1;
while(t--)
solve();
return 0;
}
- python版本
import math
PI = math.acos(-1)
def f(x, y):
return (x / math.cos(y / 180.0 * PI))
def solve():
a, b = map(float, input().split())
if a > b:
a, b = b, a
l, r = 0.0, 30.0
while abs(r - l) > 1e-10:
mid = (l + r) / 2.0
if f(a, mid) < f(b, 30 - mid):
l = mid
else:
r = mid
n = f(a, l)
area = n * n * math.sqrt(3) / 4.0
rest = a * b - area
res = area * 1000000
ans = rest * 1000000
print(n)
if res > ans:
print("Frog")
else:
print("Fish")
T = 1
for _ in range(T):
solve()
C.CCPC秦皇岛的奖牌
题目描述
2023年10月15日,第九届大学生程序设计竞赛CCPC秦皇岛分站赛,华北理工大学的小龙和小旭再一次突破自我,同样也突破了学校的最好成绩,第一次拿到了CCPC的铜牌,如下图片为此次获得的铜牌。
华北理工大学,自2018年开始参加CCPC大赛,真正取得参赛资格的是2020年,经过5年的艰苦训练和持之以恒不畏强手的精神,这届最终站在领奖台上!正所谓一代更比一代强,集训队的小Y就对未来进行了憧憬,想象未来华北理工大学也会像东北大学秦皇岛分校一样,ACM实验的奖牌不是竖着放的,而是摞起来放的,小Y联想到这,他想问你个问题,现在有编号从 1 到 n(1≤n≤100000) 的n块不同的奖牌,初始时每块奖牌单独为一列,小Y会对这些奖牌进行 q 次操作。操作分为两种:
-
小Y选择两个整数 x,y,将编号为 x 的奖牌所在的列放到编号为 y 的奖牌所在列的正上方。
-
小Y给你一个整数 x,询问你编号为 x 的奖牌上方或者下方有多少块奖牌。
请你对每次询问操作输出正确答案。
输入
第一行包含一个整数 \(q(1 \leqslant q \leqslant10^5)\),代表小Y的操作次数。
之后 q 行,每行代表一次操作,两种操作会以下形式给出:
M x y (\(1 \leqslant x,y\leqslant n \leqslant10^5\)),代表移动操作,数据保证编号为 x,y 的两块奖牌不会位于同一列。。
U x($1 \leqslant x \leqslant n $),代表询问x上方的奖牌数量操作。
D x($1 \leqslant x \leqslant n $), 代表询问x下方的奖牌数量操作。
注意本题不会给出 n 的值。
输出
对于每个询问操作,输出一个整数,代表编号为 x 的奖牌上方或者下方有多少块奖牌。
样例输入
6 M 1 3 M 2 4 D 3 U 2 M 4 5 D 2
样例输出
0 0 2
标程
- C 版本
#include<stdio.h>
#include<stdlib.h>
#define N 100010
typedef struct DSU
{
int f[N];
int siz[N];
int dist[N];
} DSU;
void init(DSU* dsu, int n)
{
for (int i = 0; i < n; i++)
{
dsu->f[i] = i;
dsu->siz[i] = 1;
dsu->dist[i] = 0;
}
}
int leader(DSU* dsu, int x)
{
if (x != dsu->f[x])
{
int u = leader(dsu, dsu->f[x]);
dsu->dist[x] += dsu->dist[dsu->f[x]];
dsu->f[x] = u;
}
return dsu->f[x];
}
int same(DSU* dsu, int u, int v)
{
return leader(dsu, u) == leader(dsu, v);
}
int merge(DSU* dsu, int u, int v)
{
u = leader(dsu, u);
v = leader(dsu, v);
if (u == v)
return 0;
dsu->f[u] = v;
dsu->dist[u] = dsu->siz[v];
dsu->siz[v] += dsu->siz[u];
return 1;
}
int size(DSU* dsu, int x)
{
return dsu->siz[leader(dsu, x)];
}
void solve()
{
DSU dsu1, dsu2;
int n;
scanf("%d", &n);
init(&dsu1, N);
init(&dsu2, N);
char op[2];
int x, y;
while (n--)
{
scanf("%s %d", op, &x);
if (op[0] == 'M')
{
scanf("%d", &y);
merge(&dsu1, x, y);
merge(&dsu2, y, x);
}
else
{
leader(&dsu1, x);
leader(&dsu2, x);
if (op[0] == 'U')
printf("%d\n", dsu2.dist[x]);
else
printf("%d\n", dsu1.dist[x]);
}
}
}
int main()
{
int t = 1;
while (t--)
solve();
return 0;
}
- C++ 版本
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
struct DSU
{
vector<int> f, siz, dist;
DSU(int n):f(n), siz(n, 1), dist(n, 0){iota(f.begin(), f.end(), 0);}
int leader(int x)
{
if(x != f[x])
{
auto u = leader(f[x]);
dist[x] += dist[f[x]];
f[x] = u;
}
return f[x];
}
bool same(int u, int v)
{
return leader(u) == leader(v);
}
bool merge(int u, int v)
{
u = leader(u);
v = leader(v);
if(u == v) return false;
f[u] = v;
dist[u] = siz[v];
siz[v] += siz[u];
return true;
}
int size(int x)
{
return siz[leader(x)];
}
};
void solve()
{
DSU dsu1(N), dsu2(N);
int n;
cin >> n;
string op;
int x, y;
while(n--)
{
cin >> op >> x;
if(op == "M")
{
cin >> y;
dsu1.merge(x, y);
dsu2.merge(y, x);
}
else
{
dsu1.leader(x);
dsu2.leader(x);
if(op == "U")
cout << dsu2.dist[x] << "\n";
else
cout << dsu1.dist[x] << "\n";
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1;
while(t--)
solve();
return 0;
}
- python版本
import sys
from collections import defaultdict
sys.setrecursionlimit(100000)
class DSU:
def __init__(self, n):
self.f = list(range(n))
self.siz = [1] * n
self.dist = [0] * n
def leader(self, x):
if self.f[x] != x:
u = self.leader(self.f[x])
self.dist[x] += self.dist[self.f[x]]
self.f[x] = u
return self.f[x]
def same(self, u, v):
return self.leader(u) == self.leader(v)
def merge(self, u, v):
u = self.leader(u)
v = self.leader(v)
if u == v:
return False
self.f[u] = v
self.dist[u] = self.siz[v]
self.siz[v] += self.siz[u]
return True
def size(self, x):
return self.siz[self.leader(x)]
def solve():
N = 100010
dsu1 = DSU(N)
dsu2 = DSU(N)
n = int(input())
for _ in range(n):
op = input().split()
x = int(op[1])
if op[0] == "M":
y = int(op[2])
dsu1.merge(x, y)
dsu2.merge(y, x)
else:
dsu1.leader(x)
dsu2.leader(x)
if op[0] == "U":
print(dsu2.dist[x])
else:
print(dsu1.dist[x])
T = 1
for _ in range(T):
solve()
D.Difficult的线段
题目描述

第45届国际大学生程序设计竞赛全球总决赛( ICPC World Finals),2022年11月10日在孟加拉国达卡市举办。
该竞赛被誉为“计算机软件领域的奥林匹克”,北京大学信息科学技术学院的孔朝哲、周雨扬、潘骏跃三名本科生组成的北大代表队,在计算机学院罗国杰和信息科学技术学院张勤健两位老师的指导下,获得本次竞赛金牌,名列全球第二名。
决赛的前两个小时,赛程并非一帆风顺。他们花了48分钟才通过了第一道题目,而对手麻省理工学院队在第50分钟时就已经通过了四道题目。大比分落后的情况下,成员们并没有气馁,他们互相鼓励,调整好心态。在落后第一名三道题的情况下,仍然发挥了最好的水平,并以第二名的好成绩摘得金牌。
他们齐心协力,逆风翻盘,值得我们学习,但是当前参加NCST-ACM校赛的你只有一个人在孤军奋战,现在需要你解决一道”难“题,希望你自我鼓励,调整好心态,给你一个整数 N。考虑坐标轴上所有可能的线段,这些线段的端点位于坐标介于 0 和 N 之间的整数点(包括 0 和 N 之间);将会有总数为\(\frac{n(n + 1)}{2}\)的线段。现在希望你在多个图层中绘制这些线段,以便在每个图层中这些线段不会重叠(不过它们可能会在端点处接触)。你不能将这些线段移动到坐标轴上的不同位置。请你找出给定的 N 所需的最少图层数。
输入
一个\(t(t \leqslant 10^5)\),表示t组测试样例
对于每组测试样例,输入行包含一个整数 \(N (1 \leqslant N \leqslant10^{18})\)。
输出
对于每组测试样例,输出一个整数为给定的 N 绘制线段所需的最小图层数。
样例输入
3 2 3 4
样例输出
2 4 6
注意
当N = 4时线段及其最佳分层排列的情况:

标程
- C 高精度版本
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define int long long
typedef long long i64;
void mul(char a[], i64 b)
{
int p = 0;
char c[1000] = {};
int n = strlen(a);
for(int i = 0; i < n || p; i++)
{
if(i < n) p += (a[i] - '0') * b;
char e[2] = {p % 10 + '0', '\0' };
strcat(c, e);
p /= 10;
}
while(c[strlen(c) - 1] == '0' && strlen(c) > 2) c[strlen(c) - 1] = '\0';
for(int i = strlen(c) - 1; i >= 0; i--) printf("%c", c[i]);
printf("\n");
}
void solve()
{
i64 n;
scanf("%lld", &n);
i64 a = (n - 1)/ 2 + 1;
i64 b = n - (n - 1) / 2;
char s1[1000]={};
while(a)
{
char e[2] = {a % 10 + '0', '\0' };
strcat(s1, e);
a /= 10;
}
mul(s1, b);
}
signed main()
{
int t;
scanf("%lld", &t);
while(t--)
solve();
return 0;
}
- C++ 高精度版本
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
string operator*(string a, i64 b)
{
i64 p = 0;
string c;
for(int i = 0; i < a.size() || p; i++)
{
if(i < a.size()) p += (a[i] - '0') * b;
c += p % 10 + '0';
p /= 10;
}
while(c.back() == '0' && c.size() > 1) c.pop_back();
reverse(c.begin(), c.end());
return c;
}
void solve()
{
i64 n;
cin >> n;
i64 a = (n - 1)/ 2 + 1;
i64 b = n - (n - 1) / 2;
string s1;
while(a)
{
s1 += a % 10 + '0';
a /= 10;
}
cout << s1 * b << "\n";
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while(t--)
solve();
return 0;
}
-
C++__int128版本
-
首先说明一下:
-
C/C++标准IO是不认识
__int128这种数据类型的,cin和cout是无法输出__int128的,所以我们要自己实现输入输出,其他的运算,与int没有什么不同。可以对long long直接强转成
__int128
__int128能直接做加减乘除赋值
#include <bits/stdc++.h>
using namespace std;
template <typename T>
T read()
{
T sum = 0, fl = 1;
int ch = getchar();
for (; !isdigit(ch); ch = getchar())
if (ch == '-') fl = -1;
for (; isdigit(ch); ch = getchar()) sum = sum * 10 + ch - '0';
return sum * fl;
}
template <typename T>
void print(T x)
{
if (x < 0)
{
x = -x;
putchar('-');
}
if (x > 9) print(x / 10);
putchar(x % 10 + '0');
}
void solve()
{
__int128 n = read<__int128>();
__int128 a = (n - 1) / 2 + 1;
__int128 b = n - (n - 1) / 2;
print(a * b);
puts("");
}
int main()
{
int t;
cin >> t;
while(t--)
solve();
return 0;
}
- python版本
def solve():
n = int(input())
a = (n - 1)// 2 + 1
b = n - (n - 1) // 2
print(a * b)
T = int(input())
for _ in range(T):
solve()
E.Easy的座位安排
问题描述
Potremz和Wood是两个资深的OI佬,这两个灵魂搭档在2023年10月份凭借HBCPC河北省大学生程序设计竞赛一等奖获得的名额,再一次合作参加了东秦的CCPC线下国赛,但是现在Potremz的学弟S_zhi对CCPC的这个标志和CCPC的每个队伍的座位安排不是很了解,Potremz细心解释了CCPC的标志含义,正如以下图片所示。

红色和黄色的C可以看成CCPC的前两个字母C,绿色的P就是代表CCPC第三个字母P,那么和绿色相接的蓝色的C就是CCPC的第四个字母C,当然最重要的是还得知道CCPC是China Collegiate Programming Contest的简写,这个问题就顺利解决了。
但是CCPC的每个队伍的座位安排,Wood觉得不用解释,如下图所示,就是简单的假如赛场有\(n\times n\)个桌子,每张桌子会有一支参赛队伍。

听到这些,S_zhi终于悟了,联想到校赛正好在紧张的筹备当中,作为负责人的他想到座位安排也可以这样,但是由于安排比赛场地的桌子的间距已经固定,现在前后左右的桌子的间距不足以使得参赛选手正常参赛,间距过于窄,校赛马上要开始了,S_zhi邀请你给他设计一个方案,"C"表示安排座位, "."表示空出座位,使得给定的\(n \times n\)个桌子可以容纳最多的参赛选手。
输入
第一行包含一个整数n(2 ≤ n ≤ 1000).
输出
第一行打印一个整数,即可以安排座位的最大数量。
接下来每n行打印n个字符,描述座位的配置。对于不摆放桌子的地方,打印".";对于安排摆放桌子的地方,打印"C"。
如果有多个正确答案,可以打印任意一个。
样例输入
3
样例输出
5 C.C .C. C.C
标程
- C 版本
#include <stdio.h>
void solve()
{
int n;
scanf("%d", &n);
printf("%d\n", (n * n + 1) / 2);
for (int i = 0; i < n; i++)
{
if (i % 2)
{
for (int j = 0; j < n; j++)
{
if (j % 2) printf("C");
else printf(".");
}
}
else
{
for (int j = 0; j < n; j++)
{
if (j % 2) printf(".");
else printf("C");
}
}
printf("\n");
}
}
int main()
{
int t = 1;
while (t--)
solve();
return 0;
}
- C++ 版本
#include<bits/stdc++.h>
using namespace std;
void solve()
{
int n;
cin >> n;
cout << (n * n + 1 )/ 2 << "\n";
for(int i = 0; i < n; i++)
{
if(i % 2)
{
for(int j = 0; j < n; j++)
{
if(j % 2) cout << 'C';
else cout << '.';
}
}
else
{
for(int j = 0; j < n; j++)
{
if(j % 2) cout << '.';
else cout << 'C';
}
}
cout << "\n";
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1;
while(t--)
solve();
return 0;
}
- python版本
def solve():
n = int(input())
print((n * n + 1) // 2)
for i in range(n):
if i % 2 == 1:
for j in range(n):
if j % 2 == 0:
print('.', end='')
else:
print('C', end='')
else:
for j in range(n):
if j % 2 == 0:
print('C', end='')
else:
print('.', end='')
print()
T = 1
for _ in range(T):
solve()
F.Fall的校赛
问题描述
刚刚参加完2023年ACM协会C语言程序设计基础培训的Alice和Bob由于达到全勤,十分兴奋,他们由此对编程十分感兴趣,他们想进一步了解编程竞赛,他们了解到学校的参加的ACM竞赛(括号内为竞赛对应的简称):
- 华北理工大学生程序设计大赛(NCSTCPC)
- 国际大学生程序设计大赛(ICPC)
- 中国大学生程序设计大赛(CCPC)
- 蓝桥杯全国软件和信息技术专业人才大赛(lanqiao)
- 中国高校计算机团体程序设计天梯赛(GPLT)
- 百度之星程序设计大赛(Astar)
- 河北省大学生程序设计大赛(HBCPC)
他们把大赛的全称都记住了,但是英文字母简称没有记住,希望你可以帮他们回忆回忆。
输入
无
输出
总共7行,每行输出一个大赛的简称(严格大小写,严格按照顺序输出)。
样例输入
无
样例输出
无
标程
- C 版本
#include<stdio.h>
int main()
{
printf("NCSTCPC\nICPC\nCCPC\nlanqiao\nGPLT\nAstar\nHBCPC");
return 0;
}
- C++ 版本
#include<bits/stdc++.h>
using namespace std;
void solve()
{
string s[7] = {
"NCSTCPC",
"ICPC",
"CCPC",
"lanqiao",
"GPLT",
"Astar",
"HBCPC"
};
for(int i = 0; i < 7; i++) cout << s[i] << "\n";
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1;
while(t--)
{
solve();
}
return 0;
}
- python 版本
print("NCSTCPC\nICPC\nCCPC\nlanqiao\nGPLT\nAstar\nHBCPC")
- PHP偷懒版本,直接输出
NCSTCPC
ICPC
CCPC
lanqiao
GPLT
Astar
HBCPC
G.GPLT的试炼
问题描述
GPLT,团体程序设计天梯赛,一个由十个人组成一支队伍参加的国家级比赛,省级奖项和国家级奖项通过一场竞技就可以决出,这是一个比较良心的比赛,经过jiangly、yxc、wls和dls四位大佬指导熏陶的ZsX和团队剩余的9人参加了2023年度的团体程序设计天梯赛,但是由于他对规则不是很理解,所以造成了很大的失误,没有取得应有的成绩,为了避免之后比赛的失误,他自己重新整理了一份规则,规则如下:
- 竞赛题目分 3 个梯级:
- 基础级设 8 道题,其中 5 分、10 分、15 分、20 分的题各 2 道,满分为 100 分,1~8题分数分别为5,5,10,10,15,15,20,20。
- 进阶级设 4 道题,每道题 25 分,满分为 100 分;
- 登顶级设 3 道题,每道题 30 分,满分为 90 分。
- 参赛队员可以在比赛中的任何时刻尝试解决任何梯级的题目。但只有当一支队伍的基础题总分超过 800 分时,其本队进阶部分的题目分数才被判为有效。只有当其进阶题总分超过 400 分时,其本队登顶部分的题目分数才被判为有效。
- 参赛队员的个人总分由其每题得分加先锋奖励构成。但只有当该队员的基础题总分超过 80 分时,其进阶部分的题目分数(包括奖励)才被判为对其个人有效;其进阶题总分超过 40 分时,其登顶部分的题目分数(包括奖励)才被判为对其个人有效。
通过阅读这份规则,如果你足够细心的话,你就可以发现,这真的是团体赛,对于第一阶梯的题目对于个人来说,没有超过80分,第二阶段的题目做出来不会算到个人最后的有效分数,但是对于团体的分数计算规则可以仔细扣一下,你就会发现,只要团队第一阶梯的分数总和超过800分,不管你个人的得分是否大于80,你做出来的第二阶梯的题目,加分仍然是算做团队有效分数的,所以这就是团体赛的有意思的地方,可以舍小我成就大我,namo现在给你一个团体的每个人每道题的实际得分,请你计算一下该团队最后的有效分数,以及团队每个人最后的有效分数。
输入
一共10行,每行包含15个分数,表示第i个人的15道题的实际分数,题目保证输入分数0到满分之间。
输出
输出两行。
第一行,一个整数表示团体分数
第二行,十个整数,以空格分隔开,表示之前按输入顺序团体内每个人的有效分数。
样例输入
5 5 10 10 15 15 20 20 25 25 5 25 0 6 0 5 5 10 10 15 15 20 20 25 25 16 25 0 6 0 5 5 10 10 15 15 20 20 25 25 17 25 0 2 0 5 5 10 10 15 15 20 20 25 20 2 1 0 1 0 5 5 10 10 15 15 20 20 16 7 2 0 0 0 0 5 5 10 10 15 0 19 20 25 18 1 25 0 0 0 5 5 10 10 15 12 20 20 25 25 2 25 0 1 0 5 5 10 10 15 15 4 0 0 0 2 0 0 0 0 5 5 10 10 6 0 19 20 0 3 0 0 0 0 0 5 5 10 10 15 15 15 20 25 0 0 0 0 0 0
样例输出
1443 186 197 194 149 125 153 175 64 75 120
标程
- C 版本
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct person
{
int fr, sc, ti;
}P[10];
void solve()
{
int x;
int sum1 = 0, sum2 = 0, sum3 = 0;
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 15; j++)
{
scanf("%d", &x);
if (j < 8)
P[i].fr += x;
else if (j < 12)
P[i].sc += x;
else
P[i].ti += x;
}
sum1 += P[i].fr;
sum2 += P[i].sc;
sum3 += P[i].ti;
}
int ans = 0;
ans = sum1;
if (sum1 > 800)
{
ans += sum2;
if (sum2 > 400)
ans += sum3;
}
printf("%d\n", ans);
for (int i = 0; i < 10; i++)
{
int res = P[i].fr;
if (P[i].fr > 80)
{
res += P[i].sc;
if (P[i].sc > 40)
res += P[i].ti;
}
printf("%d ", res);
}
printf("\n");
}
int main()
{
int t = 1;
while (t--)
solve();
return 0;
}
- C++ 版本
#include<bits/stdc++.h>
using namespace std;
struct person
{
int fr, sc, ti;
}P[10];
void solve()
{
int x;
int sum1 = 0, sum2 = 0, sum3 = 0;
for(int i = 0; i < 10; i++)
{
for (int j = 0; j < 15; j++)
{
cin >> x;
if (j < 8)
P[i].fr += x;
else if (j < 12)
P[i].sc += x;
else
P[i].ti += x;
}
sum1 += P[i].fr;
sum2 += P[i].sc;
sum3 += P[i].ti;
}
int ans = 0;
ans = sum1;
if(sum1 > 800)
{
ans += sum2;
if(sum2 > 400)
ans += sum3;
}
cout << ans << "\n";
for(int i = 0; i < 10; i++)
{
int res = P[i].fr;
if(P[i].fr > 80)
{
res += P[i].sc;
if(P[i].sc > 40)
res += P[i].ti;
}
cout << res << " ";
}
cout << "\n";
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1;
while(t--)
solve();
return 0;
}
- python版本
class Person:
def __init__(self, fr, sc, ti):
self.fr = fr
self.sc = sc
self.ti = ti
def solve():
x = 0
sum1, sum2, sum3 = 0, 0, 0
for i in range(10):
x = list(map(int, input().split()))
for j in range(15):
if j < 8:
P[i].fr += x[j]
elif j < 12:
P[i].sc += x[j]
else:
P[i].ti += x[j]
sum1 += P[i].fr
sum2 += P[i].sc
sum3 += P[i].ti
ans = 0
ans = sum1
if sum1 > 800:
ans += sum2
if sum2 > 400:
ans += sum3
print(ans)
for i in range(10):
res = P[i].fr
if P[i].fr > 80:
res += P[i].sc
if P[i].sc > 40:
res += P[i].ti
print(res, end=" ")
print()
P = [Person(0, 0, 0) for _ in range(10)]
T = 1
for _ in range(T):
solve()
H.Honour的揽月湾激光
题目描述
华北理工大学坐落于河北省唐山市曹妃甸区,谈到曹妃甸区的风景名胜,不得不谈一谈为数不多的揽月湾旅游景区,揽月湾旅游景区坐落于美丽的渤海湾,被誉为“离北京最近的海”,是曹妃甸落实“京津冀协同发展”战略、践行向海图强、向海发展而重点打造的“京津冀滨海微度假目的地”。景区形似一弯新月,悬挂于美丽的渤海湾,呈“海上生明月”之景,展“上九天揽月”之情,故此命名“揽月湾”。

夜幕降临,灯光映衬下的揽月湾甚是美丽,城堡上的激光也是十分耀眼,国庆期间,小唐陪着朋友来到了揽月湾,看到城堡上的激光,它们都向四周发散,会形成一些交点,小唐想知道这些交点的坐标,求你来解决这个问题,为简化问题,现在想象在一个三维空间,在该空间中,只有两个激光发射器,也就是只会发射两束激光,两个激光发射器的位置位于两个正三角形区域的重心,并且激光只会沿着两个重心连线的方向进行扫射,这里的正三角形区域的z轴坐标一定为0,现在给出你两个正三角形三个点的xy轴位置坐标和两个激光发射器发射的激光经过的某一个点的xz轴坐标,请你求出两束激光交点的坐标,为进一步简化问题,题目保证两个重心连线的方向一定是沿着x轴的,并且保证给出发射激光经过的某一个点的坐标一定在两个重心连线的方向与xoy平面垂直的平面上,并且保证两束激光一定会有交点。
输入
总共输入四行。
前两行每行输入六个坐标值,每两个坐标值代表三角形其中一点的xy坐标值(\(\mid x \mid,\mid y \mid \leqslant 100.0\))。
后两行每行输入两个坐标值,每行表示一个发射激光经过的某一个点的xz坐标(\(\mid x \mid,\mid y \mid \leqslant 100.0\))
输出
输出三个数,表示两束激光交点的xyz坐标值,结果保留五位小数。
样例输入
1 3 -0.7320508 0 2.7320508 0 5 3 3.2679491 0 6.7320508 0 3 2 3 2
样例输出
3.00000 1.00000 2.00000
标程
- C 版本
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
typedef struct Point
{
double x, y;
} Point;
const int N = 5000 + 10;
int n, cnt;
Point add(Point a, Point b) {
Point c;
c.x = a.x + b.x;
c.y = a.y + b.y;
return c;
}
Point sub(Point a, Point b) {
Point c;
c.x = a.x - b.x;
c.y = a.y - b.y;
return c;
}
Point multiply(Point a, double t) {
Point c;
c.x = a.x * t;
c.y = a.y * t;
return c;
}
double dp(Point a, Point b) {
return a.x * b.y - a.y * b.x;
}
Point getNode(Point a, Point u, Point b, Point v) {
double t = dp(sub(a, b), v) / (dp(v, u));
Point p;
p.x = a.x + u.x * t;
p.y = a.y + u.y * t;
return p;
}
void solve()
{
double x, y;
Point s1;
s1.x = 0;
s1.y = 0;
for(int i = 0; i < 3; i++)
{
scanf("%lf %lf", &x, &y);
s1.x += x;
s1.y += y;
}
s1.x /= 3;
s1.y /= 3;
Point s2;
s2.x = 0;
s2.y = 0;
for(int i = 0; i < 3; i++)
{
scanf("%lf %lf", &x, &y);
s2.x += x;
s2.y += y;
}
s2.x /= 3;
s2.y /= 3;
double y1 = s2.y;
scanf("%lf %lf", &x, &y);
Point a;
a.x = x;
a.y = y;
scanf("%lf %lf", &x, &y);
Point b;
b.x = x;
b.y = y;
s1.y = 0;
s2.y = 0;
Point c = getNode(a, sub(s1, a), b, sub(s2, b));
printf("%.5lf %.5lf %.5lf\n", c.x, y1, c.y);
}
int main()
{
int t = 1;
while(t--)
solve();
return 0;
}
- C++ 版本
#include<bits/stdc++.h>
using namespace std;
struct Point
{
Point(double x, double y)
{
this->x = x;
this->y = y;
}
double x, y;
};
const int N = 5e3 + 10;
int n, cnt;
Point operator+(Point a, Point b)
{
return Point(a.x + b.x, a.y + b.y);
}
Point operator-(Point a, Point b)
{
return Point(a.x - b.x, a.y - b.y);
}
Point operator*(Point a, double t)
{
return Point(a.x * t, a.y * t);
}
double operator*(Point a, Point b)
{
return a.x * b.y - a.y * b.x;
}
Point getNode(Point a, Point u, Point b, Point v)
{
double t = (a - b) * v / ((v * u) == 0 ? 1:(v * u));
Point p = a + u * t;
return p;
}
void solve()
{
double x, y;
Point s1(0, 0);
for(int i = 0; i < 3; i++)
{
cin >> x >> y;
s1.x += x;
s1.y += y;
}
s1.x /= 3;
s1.y /= 3;
Point s2(0, 0);
for(int i = 0; i < 3; i++)
{
cin >> x >> y;
s2.x += x;
s2.y += y;
}
s2.x /= 3;
s2.y /= 3;
double y1 = s2.y;
cin >> x >> y;
Point a(x, y);
cin >> x >> y;
Point b(x, y);
s1.y = 0;
s2.y = 0;
Point c = getNode(a, s1 - a, b, s2 - b);
cout << fixed << setprecision(5) << c.x << " " << y1 << " " << c.y << "\n";
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1;
while(t--)
solve();
return 0;
}
- python版本
import math
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
return Point(self.x + other.x, self.y + other.y)
def __sub__(self, other):
return Point(self.x - other.x, self.y - other.y)
def __mul__(self, other):
return Point(self.x * other, self.y * other)
def dot(self, other):
return self.x * other.y - self.y * other.x
def get_node(a, u, b, v):
t = (a - b).dot(v) / ((v.dot(u) == 0) and 1 or v.dot(u))
p = a + u * t
return p
def solve():
s1 = Point(0, 0)
x1, y1, x2, y2, x3, y3 = map(float, input().split())
s1.x += x1
s1.y += y1
s1.x += x2
s1.y += y2
s1.x += x3
s1.y += y3
s1.x /= 3
s1.y /= 3
s2 = Point(0, 0)
x1, y1, x2, y2, x3, y3 = map(float, input().split())
s2.x += x1
s2.y += y1
s2.x += x2
s2.y += y2
s2.x += x3
s2.y += y3
s2.x /= 3
s2.y /= 3
y1 = s2.y
x, y = [int(i) for i in input().split()]
a = Point(x, y)
x, y = [int(i) for i in input().split()]
b = Point(x, y)
s1.y = 0
s2.y = 0
c = get_node(a, s1 - a, b, s2 - b)
print(f"{c.x:.5f} {y1:.5f} {c.y:.5f}")
T = 1
for _ in range(T):
solve()
I.ICPC的气球
题目描述
出征完CCPC的小龙和小旭再过五六天就要冲击第48届ICPC国际大学生程序设计竞赛亚洲区域赛济南赛站,ICPC,国际大学生程序设计竞赛,对于该竞赛我校最好的成绩也就只是优胜奖,也就类似于成功参与奖,期待今年第48届,龙旭组合可以冲击学校的新高度,如上图片为ICPC的logo,蓝色的云可以代表思考题目,黄色的灯泡可以代表思路想到了,红色的气球可以表示AC(通过)题目了,气球挂起来了,希望他们可以气球挂起的越多越好。
为了给小龙和小旭出征ICPC济南站加油打气,需要你统计气球数,如果对于给定的区间左右边界内的气球总数都统计正确了,你就完成了你的加油打气任务,现在给出ICPC某一次比赛的n个队伍,每个队伍封榜前都有一个透明的通过题数,排行榜会实时更新,由于比赛的赛制,总共比赛五个小时,最后一个小时会有一个封榜的操作,所以最后一个小时整个赛场的排名不会进行改变,停留在最后一小时前的状态,你在排行榜中只能看到每个队伍最后是否交了题目,但是不了解他们是否AC(通过)了这道题,比较神奇的是,气球是实时更新的,所以附近人的过题情况你是可以知道的,但是现在为了考验你,气球不再实时更新了,现在给你n个队伍封榜前的AC题目数量,并给出你如下两种操作:
- "A" l r x, 表示对于编号由l到r(l和r都包括)的队伍在最后一个小时通过的题目数都为x。
- "Q" l r, 表示询问你队伍编号由l到r(l和r都包括)的队伍的气球总数。
回答对于每一个询问,区间l到r的总的气球数。
输入
第一行两个整数N和M(\(1 \leqslant N,M\leqslant1\times10^5\)), N表示队伍总数, M表示操作个数。
第二行N个整数
,
,表示每支队伍前四个小时(封榜前)的过题数目。
之后M行,每行包括"A"和"Q"两种操作之一。
"A" l r x(
), 表示对于编号由l到r(l和r都包括)的队伍都在最后一个小时通过的部分题目数。
"Q" l r, 表示询问你队伍编号由l到r(l和r都包括)的队伍的气球总数,由于答案可能会很大,请你将结果对998244353取模后再返回。
输出
对于每个询问操作,输出一个整数,代表给定队伍区间的气球总数,由于答案可能会很大,请你将结果对998244353取模后再返回。
样例输入
5 4 1 2 3 4 5 A 1 4 2 Q 2 5 A 1 5 3 Q 3 3
样例输出
20 8
注意
注意,因为滚榜解榜的时候,每次解榜只是展示轮到队伍的过的第一道题,本题题目修改规则,每次增加的不仅仅一道题,每次可以增加指定的数量的题目,所以一支队伍不只会增加一次题目数量,一支队伍可能会增加很多次通过的题目数量。
标程
- C 版本
#include<stdio.h>
#define int long long
#define N 200050
#define mod 998244353
int tree[N * 10], lzy[N * 10];
void pushup(int o)
{
tree[o] = (tree[o << 1] + tree[o << 1 | 1]) % mod;
}
void build(int o, int l, int r)
{
if(l > r) return;
if(l == r)
{
scanf("%lld", &tree[o]);
return;
}
int mid = (l + r) / 2;
build(o << 1, l, mid);
build(o << 1 | 1, mid + 1, r);
pushup(o);
}
void pushdown(int o,int l,int r)
{
int mid = (l + r) / 2;
tree[o << 1] += ((mid - l + 1) * lzy[o]) % mod;
tree[o << 1] %= mod;
tree[o << 1 | 1] += ((r - mid) * lzy[o]) % mod;
tree[o << 1] %= mod;
lzy[o << 1] += lzy[o];
lzy[o << 1] %= mod;
lzy[o << 1 | 1] += lzy[o];
lzy[o << 1] %= mod;
lzy[o] = 0;
}
void modify(int o, int l, int r, int L, int R, int v)
{
if(l > r) return;
pushdown(o, l, r);
if(L <= l && r <= R)
{
tree[o] += ((r - l + 1) * v) % mod;
tree[o] %= mod;
lzy[o] += v;
lzy[o] %= mod;
return;
}
int mid = l + r >> 1;
if(L <= mid) modify(o << 1, l, mid, L, R, v);
if(R > mid) modify(o << 1 | 1, mid + 1, r, L, R, v);
pushup(o);
}
int query(int o, int l, int r, int L, int R)
{
pushdown(o, l, r);
if(L <= l && r <= R)
{
return tree[o] % mod;
}
int mid = l + r >> 1;
int ans = 0;
if(L <= mid) ans += query(o << 1, l, mid, L, R) %mod, ans %= mod;
if(R > mid) ans += query(o << 1 | 1, mid + 1, r, L, R) % mod, ans %= mod;
return ans;
}
void solve()
{
int n, m;
scanf("%lld %lld", &n, &m);
build(1, 1, n);
char op[2];
int l, r, x;
while(m--)
{
scanf("%s %lld %lld", op, &l, &r);
if(*op == 'A')
{
scanf("%lld", &x);
modify(1, 1, n, l, r, x);
}
else
{
printf("%lld\n", query(1, 1, n, l, r));
}
}
}
signed main()
{
int t = 1;
while(t--)
{
solve();
}
return 0;
}
- C++ 版本
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e5 + 10, mod = 998244353;
int tree[N * 10], lzy[N * 10];
void pushup(int o)
{
tree[o] = (tree[o << 1] + tree[o << 1 | 1]) % mod;
}
void build(int o, int l, int r)
{
if(l > r) return;
if(l == r)
{
cin >> tree[o];
return;
}
int mid = (l + r) / 2;
build(o << 1, l, mid);
build(o << 1 | 1, mid + 1, r);
pushup(o);
}
void pushdown(int o,int l,int r)
{
int mid = (l + r) / 2;
(tree[o << 1] += ((mid - l + 1) * lzy[o]) % mod) %= mod;
(tree[o << 1 | 1] += ((r - mid) * lzy[o]) % mod) %= mod;
(lzy[o << 1] += lzy[o]) %= mod;
(lzy[o << 1 | 1] += lzy[o]) %= mod;
lzy[o] = 0;
}
void modify(int o, int l, int r, int L, int R, int v)
{
if(l > r) return;
pushdown(o, l, r);
if(L <= l && r <= R)
{
(tree[o] += ((r - l + 1) * v) % mod) %= mod;
(lzy[o] += v) %= mod;
return;
}
int mid = l + r >> 1;
if(L <= mid) modify(o << 1, l, mid, L, R, v);
if(R > mid) modify(o << 1 | 1, mid + 1, r, L, R, v);
pushup(o);
}
int query(int o, int l, int r, int L, int R)
{
pushdown(o, l, r);
if(L <= l && r <= R)
{
return tree[o] % mod;
}
int mid = l + r >> 1;
int ans = 0;
if(L <= mid) (ans += query(o << 1, l, mid, L, R) %mod) %= mod;
if(R > mid) (ans += query(o << 1 | 1, mid + 1, r, L, R) % mod) %= mod;
return ans;
}
void solve()
{
int n, m;
cin >> n >> m;
build(1, 1, n);
string op;
int l, r, x;
while(m--)
{
cin >> op >> l >> r;
if(op == "A")
{
cin >> x;
modify(1, 1, n, l, r, x);
}
else
{
cout << query(1, 1, n, l, r) << "\n";
}
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1;
while(t--)
{
solve();
}
return 0;
}
- python版本
import sys
N = 200001
mod = 998244353
tree = [0] * (N * 10)
lzy = [0] * (N * 10)
a = []
def pushup(o):
tree[o] = (tree[o << 1] + tree[o << 1 | 1]) % mod
def build(o, l, r):
global a
if l > r:
return
if l == r:
tree[o] = a[l]
return
mid = (l + r) // 2
build(o << 1, l, mid)
build(o << 1 | 1, mid + 1, r)
pushup(o)
def pushdown(o, l, r):
mid = (l + r) // 2
tree[o << 1] += ((mid - l + 1) * lzy[o]) % mod
tree[o << 1] %= mod
tree[o << 1 | 1] += ((r - mid) * lzy[o]) % mod
tree[o << 1 | 1] %= mod
lzy[o << 1] += lzy[o]
lzy[o << 1] %= mod
lzy[o << 1 | 1] += lzy[o]
lzy[o << 1 | 1] %= mod
lzy[o] = 0
def modify(o, l, r, L, R, v):
if l > r:
return
pushdown(o, l, r)
if L <= l and r <= R:
tree[o] += ((r - l + 1) * v) % mod
tree[o] %= mod
lzy[o] += v
lzy[o] %= mod
return
mid = (l + r) // 2
if L <= mid:
modify(o << 1, l, mid, L, R, v)
if R > mid:
modify(o << 1 | 1, mid + 1, r, L, R, v)
pushup(o)
def query(o, l, r, L, R):
pushdown(o, l, r)
if L <= l and r <= R:
return tree[o] % mod
mid = (l + r) // 2
ans = 0
if L <= mid:
ans += query(o << 1, l, mid, L, R) % mod
if R > mid:
ans += query(o << 1 | 1, mid + 1, r, L, R) % mod
return ans
def solve():
global a
n, m = map(int, input().split())
arr = input()
a.append(0)
for i in arr.split():
a.append(int(i))
build(1, 1, n)
for i in range(m):
num = input().split()
l, r = int(num[1]), int(num[2])
if num[0] == "A":
x = int(num[3])
modify(1, 1, n, l, r, x)
else:
print(query(1, 1, n, l, r) % mod)
T = 1
for i in range(T):
solve()
J.Jianlyfan的整肃
问题描述
jianglyfan对学校OJ许多人的用户ID感到非常不满,因为他们的用户ID一部分是一个单词中混用大小写字母。因此,他决定整顿这种情况,他在ACM协会大群里发出通知:

学校OJ的用户ID现在需要整肃一下,请用户ID是一个单词中混用大小写字母的用户修改用户ID,修改的用户ID使其要么只包含小写字母,要么只包含大写字母,而且在这种情况下,单词中应尽可能少地更改字母。例如,AcM必须替换为ACM,而Ncst则替换为ncst。如果一个单词包含相同数量的大写字母和小写字母,则应将所有字母替换为大写字母。例如,Oj应替换为OJ。
但是jianglyfan发现有部分人没有作出修改,现在需要你给进行按照通知规则进行修改。
输入
第一行包含一个整数t(t > 0),表示有t人没有作出修改。
第2行到第t + 1行, 每行包含一个单词s--它由大写和小写拉丁字母组成,长度从1到100。
输出
打印t个更正后的单词 s。
样例输入
3 AcM Ncst Oj
样例输出
ACM ncst OJ
标程
- C 版本
#include <stdio.h>
#include <string.h>
int is_upper(char x)
{
if (x >= 'A' && x <= 'Z')
return 1;
else
return 0;
}
void solve()
{
char s[100];
scanf("%s", s);
int up = 0;
char uc[100] = {};
char lc[100] = {};
for (int i = 0; s[i] != '\0'; i++)
{
if (is_upper(s[i]))
{
up++;
char a[2] = {s[i] , '\0'};
strcat(uc, a);
char b[2] = {s[i] - 'A' + 'a', '\0'};
strcat(lc, b);
}
else
{
char b[2] = {s[i] - 'a' + 'A', '\0'};
strcat(uc, b);
char a[2] = {s[i] , '\0'};
strcat(lc, a);
}
}
if (up >= strlen(s) - up)
printf("%s\n", uc);
else
printf("%s\n", lc);
}
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
solve();
}
return 0;
}
- C++ 版本
#include<bits/stdc++.h>
using namespace std;
bool is_upper(char x)
{
if(x >= 'A' && x <= 'Z')
return true;
else
return false;
}
void solve()
{
string s;
cin >> s;
int up = 0;
string uc;
string lc;
for(auto x : s)
{
if(is_upper(x))
{
up++;
uc += x;
lc += x - 'A' + 'a';
}
else
{
uc += x - 'a' + 'A';
lc += x;
}
}
if(up >= s.size() - up)
cout << uc << "\n";
else
cout << lc << "\n";
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while(t--)
{
solve();
}
return 0;
}
- python 版本
def is_upper(x):
if x >= 'A' and x <= 'Z':
return True
else:
return False
def solve():
s = input()
up = 0
uc, lc = '', ''
for x in s:
if is_upper(x):
up += 1
uc += x
lc += chr(ord(x) - ord('A') + ord('a'))
else:
uc += chr(ord(x) - ord('a') + ord('A'))
lc += x
if up >= len(s) - up:
print(uc)
else:
print(lc)
T = int(input())
for _ in range(T):
solve()
K.Keep books的小旭
题目描述
23级新生小旭非常热爱学习,所以他的大学生活中必不可少的就是图书馆,而小旭现在就读于华北理工大学,正如上图所示,从正门望去,科技楼和行政楼中间的就是图书馆,百年名校,群贤荟萃;渤海之滨,卷帙飘香,小旭凭借自己的成绩成功被华北理工大学的信息与计算科学专业录取,入学后经过老师和学长学姐的熏陶,他对编程十分感兴趣,他决定自己要深入自学一下算法,提高编程能力,由于他自学能力特别强,他决定去图书馆借一些编程学习书籍,就在今日,他想借一些书,这些书必须要依次借阅,但是他的精力有限,这里规定行走一米需要消耗1000精力,现在针对精力提出如下要求:
如果这些书他依次借阅完,消耗的精力:
-
在10000之内(不包括10000),那么就可以都借阅走;
-
10000~100000(不包括100000)之间,那么就需要少借一本书,你请规划少借哪一本书,才能使得小旭消耗的精力最少;
-
100000~1000000(不包括1000000)之间,那么需要少借两本书,请你规划少借哪两本连续借阅的书,才能使得小旭消耗的精力最少;
-
1000000以上,那么需要少借三本书,请你规划少借哪三本连续借阅的书,才能使得小旭消耗的精力最少;
通过以上约束规划完成后,输出小旭消耗的精力。
输入
第一行包含 1 个整数 N(N $ \leqslant 10^5$)。
以下 N − 1 行,每行包含 3 个整数 u, v 和 d(d < 1000),其中u和v分别是书架的编号(编号是从1开始到n的整数),d是书架u和书架v的距离,单位为米。
最后一行包含 N 个整数 A1, A2, . . . , AN 代表书籍借阅的顺序。
输出
一个整数,表示小旭消耗的精力,
样例输入
6 1 2 1 1 3 1 3 4 2 3 5 2 4 6 3 1 2 3 4 5 6
样例输出
8000
标程
- C 版本
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define int long long
#define swap(x, y) {int tmp = x; x = y; y = tmp;}
const int N = 100010, M = N * 2;
int flag[3] = {10, 100, 1000};
int dep[N], dist[N], fa[N][30];
int a[N];
int h[N], ne[M], e[M], W[M], idx;
void add(int a, int b, int c)
{
e[idx] = b, W[idx] = c, ne[idx] = h[a], h[a] = idx ++;
}
void dfs(int u, int Fa)
{
dep[u] = dep[Fa] + 1;
fa[u][0] = Fa;
for(int i = 1; i <= 20; i++)
{
fa[u][i] = fa[fa[u][i - 1]][i - 1];
}
for(int i = h[u]; i != -1; i = ne[i])
{
int v = e[i];
int w = W[i];
if(v == Fa) continue;
dist[v] = dist[u] + w;
dfs(v, u);
}
}
int LCA(int u, int v)
{
if(dep[v] > dep[u]) swap(u, v);
for(int i = 20; i >= 0; i--)
{
if(dep[fa[u][i]] >= dep[v])
{
u = fa[u][i];
}
}
if(u == v) return u;
for(int i = 20; i >= 0; i--)
{
if(fa[u][i] != fa[v][i])
{
u = fa[u][i];
v = fa[v][i];
}
}
return fa[u][0];
}
int path_dis(int u, int v)
{
if(!u || !v)
return 0;
return dist[u] + dist[v] - 2 * dist[LCA(u, v)];
}
int sum_dis(int i, int op)
{
int dis = 0;
dis += path_dis(a[i], a[i + op]);
for(int j = 0; j < op; j++)
{
dis -= path_dis(a[i + j], a[i + j + 1]);
}
return dis;
}
void solve()
{
int n;
scanf("%lld", &n);
memset(h, -1, sizeof(h));
for(int i = 0; i < n - 1; i++)
{
int u, v, w;
scanf("%lld%lld%lld", &u, &v, &w);
add(u, v, w);
add(v, u, w);
}
dfs(1, 0);
for(int i = 1; i <= n; i++) scanf("%lld", &a[i]);
int ans = 0;
for(int i = 1; i < n; i++)
{
ans += path_dis(a[i], a[i + 1]);
}
int res = 1e18;
if(ans > flag[2])
{
for(int i = 1; i <= n - 4; i++)
{
res = (res < ans + sum_dis(i, 4)) ? res : ans + sum_dis(i, 4);
}
}
else if(ans > flag[1])
{
for(int i = 1; i <= n - 3; i++)
{
res = (res < ans + sum_dis(i, 3)) ? res : ans + sum_dis(i, 3);
}
}
else if(ans > flag[0])
{
for(int i = 1; i <= n - 2; i++)
{
res = (res < ans + sum_dis(i, 2)) ? res : ans + sum_dis(i, 2);
}
}
else res = ans;
printf("%lld\n", res * 1000);
}
signed main()
{
int t = 1;
while(t--)
solve();
return 0;
}
- C++ 版本
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5 + 10;
int flag[3] = {10, 100, 1000};
vector<int> e[N], W[N];
int dep[N], dist[N];
vector<int> a(N);
int fa[N][30];
void dfs(int u, int Fa)
{
dep[u] = dep[Fa] + 1;
fa[u][0] = Fa;
for(int i = 1; i <= 20; i++)
{
fa[u][i] = fa[fa[u][i - 1]][i - 1];
}
for(int i = 0; i < e[u].size(); i++)
{
auto v = e[u][i];
auto w = W[u][i];
if(v == Fa) continue;
dist[v] = dist[u] + w;
dfs(v, u);
}
}
int LCA(int u, int v)
{
if(dep[v] > dep[u]) swap(u, v);
for(int i = 20; i >= 0; i--)
{
if(dep[fa[u][i]] >= dep[v])
{
u = fa[u][i];
}
}
if(u == v) return u;
for(int i = 20; i >= 0; i--)
{
if(fa[u][i] != fa[v][i])
{
u = fa[u][i];
v = fa[v][i];
}
}
return fa[u][0];
}
int path_dis(int u, int v)
{
if(!u || !v)
return 0;
return dist[u] + dist[v] - 2 * dist[LCA(u, v)];
}
int sum_dis(int i, int op)
{
int dis = 0;
dis += path_dis(a[i], a[i + op]);
for(int j = 0; j < op; j++)
{
dis -= path_dis(a[i + j], a[i + j + 1]);
}
return dis;
}
void solve()
{
int n;
cin >> n;
for(int i = 0; i < n - 1; i++)
{
int u, v, w;
cin >> u >> v >> w;
e[u].push_back(v);
W[u].push_back(w);
e[v].push_back(u);
W[v].push_back(w);
}
dfs(1, 0);
for(int i = 0; i < n; i++) cin >> a[i];
int ans = 0;
for(int i = 0; i < n - 1; i++)
{
ans += path_dis(a[i], a[i + 1]);
}
int res = 1e18;
if(ans > flag[2])
{
for(int i = 0; i < n - 4; i++)
{
res = min(res, ans + sum_dis(i, 4));
}
}
else if(ans > flag[1])
{
for(int i = 0; i < n - 3; i++)
{
res = min(res, ans + sum_dis(i, 3));
}
}
else if(ans > flag[0])
{
for(int i = 0; i < n - 2; i++)
{
res = min(res, ans + sum_dis(i, 2));
}
}
else res = ans;
cout << res * 1000 << "\n";
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1;
while(t--)
solve();
return 0;
}
- python版本
N = 100010
flag = [10, 100, 1000]
e = [[] for _ in range(N)]
W = [[] for _ in range(N)]
dep = [0] * N
dist = [0] * N
a = [0] * N
fa = [[0] * 30 for _ in range(N)]
h = [[-1] * N]
def dfs(u, Fa):
dep[u] = dep[Fa] + 1
fa[u][0] = Fa
for i in range(1, 21):
fa[u][i] = fa[fa[u][i - 1]][i - 1]
for i in range(len(e[u])):
v = e[u][i]
w = W[u][i]
if v == Fa:
continue
dist[v] = dist[u] + w
dfs(v, u)
def LCA(u, v):
if dep[v] > dep[u]:
u, v = v, u
for i in range(20, -1, -1):
if dep[fa[u][i]] >= dep[v]:
u = fa[u][i]
if u == v:
return u
for i in range(20, -1, -1):
if fa[u][i] != fa[v][i]:
u = fa[u][i]
v = fa[v][i]
return fa[u][0]
def path_dis(u, v):
if not u or not v:
return 0
return dist[u] + dist[v] - 2 * dist[LCA(u, v)]
def sum_dis(i, op):
dis = 0
dis += path_dis(a[i], a[i + op])
for j in range(op):
dis -= path_dis(a[i + j], a[i + j + 1])
return dis
def solve():
n = int(input())
for i in range(n - 1):
u, v, w = map(int, input().split())
e[u].append(v)
e[v].append(u)
W[u].append(w)
W[v].append(w)
dfs(1, 0)
a[:n] = map(int, input().split())
ans = 0
for i in range(n - 1):
ans += path_dis(a[i], a[i + 1])
res = 1e18
if ans > flag[2]:
for i in range(n - 4):
res = min(res, ans + sum_dis(i, 4))
elif ans > flag[1]:
for i in range(n - 3):
res = min(res, ans + sum_dis(i, 3))
elif ans > flag[0]:
for i in range(n - 2):
res = min(res, ans + sum_dis(i, 2))
else:
res = ans
print(res * 1000)
T = 1
for _ in range(T):
solve()
L.Library的楼梯
题目描述

23级新生小H非常热爱学习,所以她的大学生活中必不可少的就是图书馆,而小H现在就读于华北理工大学,图书馆正如上图所示,百年名校,群贤荟萃;渤海之滨,卷帙飘香,小H凭借自己的成绩成功被华北理工大学的计算机科学与技术专业录取,入学后经过老师和学长学姐的熏陶,她对编程十分感兴趣,她决定自己要深入自学一下算法,提高编程能力,由于她自学能力特别强,她决定去图书馆借一些编程学习书籍,她到了图书馆后,正好遇到了ACM集训队的同她一个专业的小司学长,小司学长看她对编程十分感兴趣,于是他给小H出了一道简单的算法入门题,面向他们前方的正式图书馆的侧边的楼梯,小司提出的问题为:
首先定义华北理工图书馆楼梯的每个台阶都会有一个美丽度,华北理工图书馆正常开馆,必须满足任何k个连续台阶中,其中最大美丽度的台阶必须大于等于M。
你现在可以进行打扫操作,也就是每次打扫都会增加1美丽值,你需要规划出执行的 最小 打扫次数,使得图书馆开馆正常,小H因为刚刚了解编程和算法,感觉有点困难,她邀请你替她解决这道题目。
输入
第一行三个整数N, k, M,(\(N \leqslant 10^5\), \(1\leqslant k\leqslant 4\))N代表台阶的总数,k代表题目要求的连续台阶个数,M代表任何k个必须满足的美丽度(\(N, M \leqslant 10^5\))。
第二行N个整数,空格间隔开,代表编号从1到N编号台阶的惊喜值h( \(h \leqslant 10^5\))。
输出
一个整数,表示最少的打扫次数。
样例输入
5 3 4 1 2 3 4 5
样例输出
1
标程
- C 版本
#include <stdio.h>
#define int long long
int INF = 1e18;
int max(int a, int b)
{
return a > b ? a : b;
}
int min(int a, int b)
{
return a < b ? a : b;
}
void solve()
{
int n, k, m;
scanf("%lld %lld %lld", &n, &k, &m);
int a[n + 1];
scanf("%lld", &a[0]);
for (int i = 1; i <= n; i++)
{
scanf("%lld", &a[i]);
}
int dp[n + 1];
for (int i = 0; i <= n; i++)
{
dp[i] = 0;
}
for (int i = 0; i < k; i++)
{
dp[i] = max(0, m - a[i]);
}
for (int i = k; i <= n - 1; i++)
{
int res = INF;
for (int j = 1; j <= k; j++)
{
res = min(res, dp[i - j]);
}
dp[i] = max(0, m - a[i]) + res;
}
int ans = INF;
for (int i = n - k; i <= n - 1; i++)
{
ans = min(ans, dp[i]);
}
printf("%lld\n", ans);
}
signed main() {
int t = 1;
while(t--)
solve();
return 0;
}
- C++ 版本
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int INF = 1e18;
void solve()
{
int n, k, m;
cin >> n >> k >> m;
vector<int> a(n);
for(auto &x : a) cin >> x;
vector<int> dp(n + 1);
for(int i = 0; i < k; i++) dp[i] = max(0ll, m - a[i]);
for(int i = k; i < n; i++)
{
int res = INF;
for(int j = 1; j <= k; j++)
{
res = min(res, dp[i - j]);
}
dp[i] = max(0ll, m - a[i]) + res;
}
int ans = INF;
for(int i = n - k; i < n; i++) ans = min(ans, dp[i]);
cout << ans << "\n";
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1;
while(t--)
{
solve();
}
return 0;
}
- python版本
import sys
sys.setrecursionlimit(1000000)
INF = 10**18
def solve():
n, k, m = map(int, input().split())
a = list(map(int, input().split()))
dp = [0] * (n + 1)
for i in range(k):
dp[i] = max(0, m - a[i])
for i in range(k, n):
res = INF
for j in range(1, k + 1):
res = min(res, dp[i - j])
dp[i] = max(0, m - a[i]) + res
ans = INF
for i in range(n - k, n):
ans = min(ans, dp[i])
print(ans)
T = 1
for _ in range(T):
solve()
M.Magic的华北理工
题目描述
“华北理工,她,位于渤海明珠,京津冀协同发展战略核心区——曹妃甸,坐落于环渤海、环京津的“两环”核心地带,她占地4500亩,她整体呈对称式布局,梅兰竹菊四个生活区,四君子傲、幽、坚、淡,文化气息浓郁,正如地图所示,建筑林立,高低错落,基础设施完备。”,
“她是一所以工、医为主,文、理、经、管、法、艺、教等多科性协调发展,具有博士硕士研究生教育、本科教育及留学生教育等教育层次和类别的省属重点骨干大学、省重点支持的国家“双一流”大学建设高校、河北省文明校园。”。
以上是华北理工大学大学生小Z参加“感恩母校行,共筑成长梦”活动分享给即将参加高考的高三学子的一段我校介绍,参加分享的小A同学通过这次分享,默默心中确立了自己的高考目标院校——华北理工大学,小A有一个爱好,喜欢刺激的滑翔伞运动,她突发奇想,华北理工大学这么多建筑,高低错落,把这些建筑排成一排,她想选择从一个建筑顶端出发,利用滑翔伞飞过尽可能多的建筑物,她为了激励自己滑翔,她给每个建筑物都有一个价值,经过这个建筑,则会获得这个建筑上的价值,她想要获得最大的价值总和,但是她对编程不是很了解,希望你通过编程告诉她,她可以获得的最大的价值总和,注意,每次滑翔,可以向相邻的建筑滑翔,并且先后经过的建筑高度必须是严格大于关系,先滑过的建筑高度严格大于后滑过的建筑高度,并且滑翔过的建筑,可以认为把该建筑从一排建筑中删除掉,对之后的滑翔不再有影响,可以通过观察第二个样例深入理解题意。
输入
第一行包含一个整数 \(T(1\leq T \leq 10^5)\),表示测试用例的组数。
对于每组测试用例:
第一行包含一个整数 \(n(1\leq n\leq 2\times 10^5)\),表示建筑的数量。
第二行包含 n 个整数 \(h_1\dots h_n(1\leq h_i\leq n)\),表示每栋建筑的高度。
第三行包含 n 个整数\(w_1\dots w_n(1\leq w_i\leq 10^9)\),表示每栋建筑的价值。
保证对于所有的测试用例,n 的总和不超过 \(2\times 10^5\)
输出
对于每组测试用例:
仅输出一行,包含一个整数,表示答案。
样例输入
2 3 2 3 2 10 10 10 5 1 1 4 3 4 20 90 66 90 88
样例输出
20 246
对于第一组测试用例:
可以先从编号为 2 的建筑开始跳跃,获得 10收益,再滑翔到编号为 1 的建筑,获得 10 收益,总收益为 20;
也可以先从编号为 2 的建筑开始跳跃,获得 10 收益,再滑翔到编号为 3 的建筑,获得 10 收益,总收益为 20。
对于第二组测试用例:
可以从编号为 3 的建筑开始跳跃,获得 66 收益,编号为3的建筑就可以忽略了,可以认为编号为2的右侧建筑由编号为3的建筑变成了编号为4的建筑。之后再滑翔到编号为 4 的建筑,获得 90 收益,再滑翔到编号为 2 的建筑,获得 90 收益,总收益为 246。
标程
- C 版本O(n)做法
#include<stdio.h>
#define N 200010
#define int long long
int h[N], lst[N], w[N], low[N], up[N];
int min(int a, int b)
{
return a < b ? a : b;
}
int max(int a, int b)
{
return a > b ? a : b;
}
void solve()
{
int n;
scanf("%lld", &n);
int res = 0;
for(int i = 1; i <= n; i++) scanf("%lld",&h[i]);
for(int i = 1; i <= n; i++) scanf("%lld",&w[i]);
for(int i = 1; i <= n; i++) w[i] += w[i - 1], lst[i] = n + 1;
up[n] = low[n] = n;
for(int i = n - 1; i > 0; i--)
{
up[i] = low[i] = i;
if(h[i + 1] > h[i]) up[i] = up[i + 1];
if(h[i + 1] < h[i]) low[i] = low[i + 1];
}
int ans = 0;
for(int i = n; i > 0; i--)
{
low[up[i]] = min(low[up[i]], lst[h[i]] - 1);
ans = max(ans, w[low[up[i]]] - w[i - 1]);
lst[h[i]] = i;
}
printf("%lld\n", ans);
}
signed main()
{
int t;
scanf("%lld", &t);
while(t--)
{
solve();
}
return 0;
}
- C 版本双指针二分做法
#include<stdio.h>
#define int long long
void solve()
{
int n;
scanf("%lld", &n);
int h[n + 10], w[n + 10];
for(int i = 1; i <= n; i++) scanf("%lld", &h[i]);
for(int i = 1; i <= n; i++)
{
scanf("%lld", &w[i]);
w[i] += w[i - 1];
}
int lst[n + 1];
for(int i = 1; i <= n; i++)
{
lst[i] = i;
if(h[i] < h[i - 1])
{
int j = i;
while(j <= n && h[j] < h[j - 1])
{
lst[j++] = i - 1;
}
i = j - 1;
}
}
int ne[n + 1];
for(int i = n; i; i--)
{
ne[i] = i;
if(h[i] < h[i + 1])
{
int j = i;
while(j && h[j] < h[j + 1])
{
ne[j--] = i + 1;
}
i = j + 1;
}
}
int pre[n + 1];
int mp[n + 1];
for(int i = 0; i < n + 1; i++) mp[i] = 0;
for(int i = 1, j = 1; i <= n; i++)
{
mp[h[i]]++;
while(j < i && mp[h[i]] > 1)
{
mp[h[j++]] --;
}
pre[i] = j;
}
int ans = 0;
for(int i = 1; i <= n; i++)
{
int l = pre[i] - 1, r = i + 1;
while(l + 1 < r)
{
int mid = l + r >> 1;
if(ne[mid] >= lst[i]) r = mid;
else l = mid;
}
int res = w[i] - w[l];
if(ans < res) ans = res;
}
printf("%lld\n",ans);
}
signed main()
{
int t;
scanf("%lld", &t);
while(t--)
{
solve();
}
return 0;
}
- C++ 版本O(n)做法
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
void solve()
{
int n;
cin >> n;
vector<i64> h(n + 1), lst(n + 1), w(n + 1), low(n + 1), up(n + 1);
i64 res = 0;
for(int i = 1; i <= n; i++) cin >> h[i];
for(int i = 1; i <= n; i++) cin >> w[i];
for(int i = 1; i <= n; i++) w[i] += w[i - 1], lst[i] = n + 1;
up[n] = low[n] = n;
for(int i = n - 1; i > 0; i--)
{
up[i] = low[i] = i;
if(h[i + 1] > h[i]) up[i] = up[i + 1];
if(h[i + 1] < h[i]) low[i] = low[i + 1];
}
i64 ans = 0;
for(int i = n; i > 0; i--)
{
i64 &p = low[up[i]];
p = min(p, lst[h[i]] - 1);
ans = max(ans, w[p] - w[i - 1]);
lst[h[i]] = i;
}
cout << ans << "\n";
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while(t--)
{
solve();
}
return 0;
}
- C++版本双指针做法
#include<bits/stdc++.h>
#define int long long
using namespace std;
void solve()
{
int n;
cin >> n;
vector<int> h(n + 10), w(n + 10);
for(int i = 1; i <= n; i++) cin >> h[i];
for(int i = 1; i <= n; i++)
{
cin >> w[i];
w[i] += w[i - 1];
}
vector<int> lst(n + 1);
for(int i = 1; i <= n; i++)
{
lst[i] = i;
if(h[i] < h[i - 1])
{
int j = i;
while(j <= n && h[j] < h[j - 1])
{
lst[j++] = i - 1;
}
i = j - 1;
}
}
vector<int> ne(n + 1);
for(int i = n; i; i--)
{
ne[i] = i;
if(h[i] < h[i + 1])
{
int j = i;
while(j && h[j] < h[j + 1])
{
ne[j--] = i + 1;
}
i = j + 1;
}
}
vector<int> pre(n + 1);
map<int,int> mp;
for(int i = 1, j = 1; i <= n; i++)
{
mp[h[i]]++;
while(j < i && mp[h[i]] > 1)
{
mp[h[j++]] --;
}
pre[i] = j;
}
int ans = 0;
for(int i = 1; i <= n; i++)
{
int l = pre[i] - 1, r = i + 1;
while(l + 1 < r)
{
int mid = l + r >> 1;
if(ne[mid] >= lst[i]) r = mid;
else l = mid;
}
int res = w[i] - w[l];
ans = max(ans, res);
}
cout << ans << "\n";
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while(t--)
{
solve();
}
return 0;
}
- python版本O(n)做法
import sys
def solve():
n = int(input())
h = [0] + list(map(int, input().split()))
w = [0] + list(map(int, input().split()))
for i in range(1, n + 1):
w[i] += w[i - 1]
lst = [n + 1] * (n + 1)
res = 0
up = [n] * (n + 1)
low = [n] * (n + 1)
up[n] = low[n] = n
for i in range(n - 1, 0, -1):
up[i] = low[i] = i
if h[i + 1] > h[i]:
up[i] = up[i + 1]
if h[i + 1] < h[i]:
low[i] = low[i + 1]
ans = 0
for i in range(n, 0, -1):
low[up[i]] = min(low[up[i]], lst[h[i]] - 1)
ans = max(ans, w[low[up[i]]] - w[i - 1])
lst[h[i]] = i
print(ans)
t = int(input())
for _ in range(t):
solve()
- Python版本双指针二分做法
import sys
def solve():
n = int(input())
h = [0] + list(map(int, input().split())) + [0]
w = [0] + list(map(int, input().split())) + [0]
for i in range(1, n + 1):
w[i] += w[i - 1]
lst = [0] * (n + 1)
i = 1
while(i <= n):
lst[i] = i
if h[i] < h[i - 1]:
j = i
while j <= n and h[j] < h[j - 1]:
lst[j] = i - 1
j += 1
i = j - 1
i += 1
ne = [0] * (n + 1)
i = n
while(i > 0):
ne[i] = i
if h[i] < h[i + 1]:
j = i
while j and h[j] < h[j + 1]:
ne[j] = i + 1
j -= 1
i = j + 1
i -= 1
pre = [0] * (n + 10)
mp = [0] * (n + 10)
j = 1
for i in range(1, n + 1):
mp[h[i]] += 1
while j < i and mp[h[i]] > 1:
mp[h[j]] -= 1
j += 1
pre[i] = j
ans = 0
for i in range(1, n + 1, 1):
l, r = pre[i] - 1, i + 1
while l + 1 < r:
mid = (l + r) // 2
if ne[mid] >= lst[i]:
r = mid
else:
l = mid
res = w[i] - w[l]
ans = max(ans, res)
print(ans)
t = int(input())
for _ in range(t):
solve()

浙公网安备 33010602011771号