传送门
A - 小红喜欢1
原题
小红拿到了一个长度为 5 的、仅由 0 和 1 组成的数组 ,其中恰好有一个 1 ,其余元素都是 0 。请你直接输出 1 所在的位置。
输入
在一行上输入五个整数 a 1 , a 2 , a 3 , a 4 , a 5 ( 0 ≤ a i ≤ 1 ) a_{1}, a_{2},a_{3},a_{4},a_{5}(0 \le a_{i} \le 1) a1,a2,a3,a4,a5(0≤ai≤1),代表小红拿到的数组
输出
在一行上输出一个整数,代表 1 1 1 所在的位置
测试样例
input1
0 0 1 0 0
output1
3
分析
- 这一题属于签到题,按顺序输入五个数,打印1所在的位置即可
#include<bits/stdc++.h>
#define all(a) a.begin(), a.end()
using i32 = int;
using u32 = unsigned int;
using i64 = long long;
using u64 = unsigned long long;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
int ans = 0;
for(int i = 1; i <= 5; i++) {
int m;
std::cin >> m;
if(m == 1) {
ans = i;
}
}
std::cout << ans;
return 0;
}
B - 小红的树切割
原题
小红定义一棵树是“好树”,当且仅当任意相邻的两个节点的颜色不同(特殊的,一个节点组成的树一定是好树)。
现在小红拿到了一棵树,一些节点被染成红色,其余节点为白色。小红希望切割若干条边形成森林,使得森林的每棵树都是“好树”。小红想知道,最少需要切割多少条边?
输入
第一行输入一个整数 n ( 2 ≤ n ≤ 1 0 5 ) n(2 \le n \le 10^5) n(2≤n≤105)代表树的节点数量。
第二行输入一个长度为 n n n,且仅由 R R R 和 W W W组成的字符串 s s s,第 i i i个字符代表第 i i i 个节点的颜色,其中 R R R 代表红色, W W W代表白色.
此后 n − 1 n - 1 n−1行,第 i i i 行输入两个整数 u i u_{i} ui 和 v i ( 1 ≤ u i , v i ≤ n ; u i ≠ v i ) v_{i}(1 \le u_{i}, v_{i} \le n; u_{i} \not= v_{i}) vi(1≤ui,vi≤n;ui=vi),链接:表示树上第 i i i 条边连接节点 u i u_{i} ui 和 v i v_{i} vi。保证树联通,没有重边。
输出
在一行上输出一个整数,代表最少需要切割的边数。
测试样例
input1
4
RWWR
1 2
2 3
3 4
output1
1
分析
- 这题类似二分图匹配,只不过我们这里是断边,所以只需要判断相邻的两个点是否是同一个颜色,如果是,则删边,否则 c o n t i n u e continue continue
#include<bits/stdc++.h>
#define all(a) a.begin(), a.end()
using i32 = int;
using u32 = unsigned int;
using i64 = long long;
using u64 = unsigned long long;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
int n;
std::cin >> n;
std::string s;
std::cin >> s;
std::vector<std::vector<int>> adj(n);
for(int i = 0; i < n - 1; i++) {
int u, v;
std::cin >> u >> v;
u--;
v--;
adj[u].push_back(v);
adj[v].push_back(u);
}
int ans = 0;
auto dfs = [&](auto self, int u, int fa) -> void {
for(auto v : adj[u]) {
if(v == fa) {
continue;
}
if(s[u] == s[v]) {
ans++;
}
self(self, v, u);
}
};
dfs(dfs, 0, -1);
std::cout << ans;
return 0;
}
C - 小红的双好数
原题
小红定义 n n n 是 k − k - k−好数,当且仅当 n n n 在 k k k 进制表示下,每一位都不大于 1 1 1 。例如, 30 30 30 是 3 − 3- 3−好数,因为 30 30 30 在三进制表示下是 ( 1010 ) 3 (1010)_{3} (1010)3.
现在输入了一个正整数 n n n,小红希望你找到两个不同的正整数 k 1 k_{1} k1 和 k 2 ( 2 ≤ k 1 < k 2 ≤ 1 0 18 ) k_{2}(2 \le k1 < k2 \le 10^{18}) k2(2≤k1<k2≤1018),满足 n n n 既是 k 1 − k_{1}- k1−好数,也是 k 2 − k_{2}- k2−好数,你能帮帮她吗?
输入
在一行上输入一个整数 n ( 1 ≤ n ≤ 1 0 18 ) n(1 \le n \le 10^{18}) n(1≤n≤1018)代表待求解的数字。
输出
如果在 [ 2 , 1 0 18 ] [2, 10^{18}] [2,1018]范围内无解,直接在一行上输出 N O NO NO;否则,先在第一行上输出 Y E S YES YES;随后,在第二行上输出两个正整数 k 1 , k 2 ( 2 ≤ k 1 < k 2 ≤ 1 0 18 ) k_{1}, k_{2}(2 \le k_{1} < k_{2} \le 10^{18}) k1,k2(2≤k1<k2≤1018),代表一组合法解。
如果存在多个解决方案,您可以输出任意一个,系统会自动判定是否正确。注意,自测运行功能可能因此返回错误结果,请自行检查答案正确性。
测试样例
input1
5
output1
YES
2 4
input2
2
output2
NO
分析
- 首先对于任意数,肯定都有一个2进制符合题意,那么我们现在要寻找另一个,假设是 x x x 进制,设 n = ( 11 ) x n = (11)_{x} n=(11)x,可解得 x = n − 1 x = n - 1 x=n−1,因此 n − 1 n - 1 n−1即是另一个进制,此时只需要对于 1 2 3 1 \space 2 \space 3 1 2 3 特判一下即可.
#include<bits/stdc++.h>
#define all(a) a.begin(), a.end()
using i32 = int;
using u32 = unsigned int;
using i64 = long long;
using u64 = unsigned long long;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
i64 n;
std::cin >> n;
if(n == 2) {
std::cout << "NO\n";
return 0;
}
std::cout << "YES\n";
if(n == 1) {
std::cout << 2 << " " << 3;
} else if(n != 3){
std::cout << 2 << " " << n - 1;
} else {
std::cout << 2 << " " << 3;
}
return 0;
}
D - 小红的线段
原题
在平面直角坐标系中有 2 × n 2 \times n 2×n个点和一条直线 y = k x + b y = kx + b y=kx+b.
小红准备在这 2 × n 2 \times n 2×n个点中连 n n n 条线段(每个点只能连接一次),她希望 和直线有交点的线段 的数量尽可能多。
请你给出一个连接方案。
输入
第一行输入三个整数 n , k , b ( 1 ≤ n ≤ 1 0 3 ; − 1 0 5 ≤ k , b ≤ 1 0 5 ) n,k,b(1 \le n \le 10^3; -10^5 \le k,b \le 10^5) n,k,b(1≤n≤103;−105≤k,b≤105)表示有 2 × n 2 \times n 2×n个点和直线 y = k x + b y = kx + b y=kx+b.
接下来 2 × n 2 \times n 2×n行,每行两个整数 x , y ( − 1 0 5 ≤ x , y ≤ 1 0 5 ) x,y(-10^5 \le x,y \le 10^5) x,y(−105≤x,y≤105)表示一个点的坐标。保证没有两个点的坐标相同。
输出
先输出一个整数 m m m,表示有 m m m 条线段和直线有交点。
接下来 n n n 行,第 i i i 行输出两个正整数 u i , v i ( 1 ≤ u i , v i ≤ 2 × n ; u i ≠ v i ) u_{i}, v_{i}(1 \le u_{i}, v_{i} \le 2 \times n; u_{i} \not = v_{i}) ui,vi(1≤ui,vi≤2×n;ui=vi)和一个字符 Y Y Y 或 N N N链接:代表连接第 u i u_{i} ui 个点和第 v i v_{i} vi 个点,以及是否和直线有交点。
如果存在多个解决方案,您可以输出任意一个,系统会自动判定是否正确。注意,自测运行功能可能因此返回错误结果,请自行检查答案正确性。
测试样例
input1
2 -1 2
0 0
0 1
1 0
1 1
output1
1
1 2 N
3 4 Y
分析
- 要使线段与直线相交,那么线段的两个点应该在直线的两边或者其中一个在直线上,因此,判断每个点与直线的关系,然后再进行处理即可
#include<bits/stdc++.h>
#define all(a) a.begin(), a.end()
using i32 = int;
using u32 = unsigned int;
using i64 = long long;
using u64 = unsigned long long;
// 点
template<class T>
struct Point {
T x;
T y;
Point(const T &x_ = 0, const T &y_ = 0) : x(x_), y(y_) {}
template<class U>
operator Point<U>() {
return Point<U>(U(x), U(y));
}
Point &operator+=(const Point &p) & {
x += p.x;
y += p.y;
return *this;
}
Point &operator-=(const Point &p) & {
x -= p.x;
y -= p.y;
return *this;
}
Point &operator*=(const T &v) & {
x *= v;
y *= v;
return *this;
}
Point &operator/=(const T &v) & {
x /= v;
y /= v;
return *this;
}
Point operator-() const {
return Point(-x, -y);
}
friend Point operator+(Point a, const Point &b) {
return a += b;
}
friend Point operator-(Point a, const Point &b) {
return a -= b;
}
friend Point operator*(Point a, const T &b) {
return a *= b;
}
friend Point operator/(Point a, const T &b) {
return a /= b;
}
friend Point operator*(const T &a, Point b) {
return b *= a;
}
friend bool operator==(const Point &a, const Point &b) {
return a.x == b.x && a.y == b.y;
}
friend std::istream &operator>>(std::istream &is, Point &p) {
return is >> p.x >> p.y;
}
friend std::ostream &operator<<(std::ostream &os, const Point &p) {
return os << "(" << p.x << ", " << p.y << ")";
}
};
// 线
template<class T>
struct Line {
Point<T> a;
Point<T> b;
Line(const Point<T> &a_ = Point<T>(), const Point<T> &b_ = Point<T>()) : a(a_), b(b_) {}
};
// 点积
template<class T>
T dot(const Point<T> &a, const Point<T> &b) {
return a.x * b.x + a.y * b.y;
}
// 叉积
template<class T>
T cross(const Point<T> &a, const Point<T> &b) {
return a.x * b.y - a.y * b.x;
}
// return x^2 + y^2
template<class T>
T square(const Point<T> &p) {
return dot(p, p);
}
// return Euclidean distance from (0,0) to the point (x,y)
// ((x - 0)^2 + (y - 0)^2) 取根号
template<class T>
double length(const Point<T> &p) {
return std::sqrt(square(p));
}
// L线段的长度
template<class T>
double length(const Line<T> &l) {
return length(l.a - l.b);
}
template<class T>
Point<T> normalize(const Point<T> &p) {
return p / length(p);
}
// 判断直线l1和l2是否平行或重合
// 平行或重合返回true 否则返回false
template<class T>
bool parallel(const Line<T> &l1, const Line<T> &l2) {
return cross(l1.b - l1.a, l2.b - l2.a) == 0;
}
// a, b两点的距离
template<class T>
double distance(const Point<T> &a, const Point<T> &b) {
return length(a - b);
}
// p点到直线l的距离
template<class T>
double distancePL(const Point<T> &p, const Line<T> &l) {
return std::abs(cross(l.a - l.b, l.a - p)) / length(l);
}
// p点到线段l的距离
template<class T>
double distancePS(const Point<T> &p, const Line<T> &l) {
if (dot(p - l.a, l.b - l.a) < 0) {
return distance(p, l.a);
}
if (dot(p - l.b, l.a - l.b) < 0) {
return distance(p, l.b);
}
return distancePL(p, l);
}
// 点a逆时针旋转90度
template<class T>
Point<T> rotate(const Point<T> &a) {
return Point(-a.y, a.x);
}
// 判断是否在x轴的上侧或y轴的右侧
// 是返回1 否返回-1
template<class T>
int sgn(const Point<T> &a) {
return a.y > 0 || (a.y == 0 && a.x > 0) ? 1 : -1;
}
// 判断点p是否在线段l的上侧
// 是返回true 否返回false
template<class T>
bool pointOnLineLeft(const Point<T> &p, const Line<T> &l) {
return cross(l.b - l.a, p - l.a) > 0;
}
// 线段l1和l2的交点坐标
template<class T>
Point<T> lineIntersection(const Line<T> &l1, const Line<T> &l2) {
return l1.a + (l1.b - l1.a) * (cross(l2.b - l2.a, l1.a - l2.a) / cross(l2.b - l2.a, l1.a - l1.b));
}
// 判断点p是否在线段l上
// 是返回true 否返回false
template<class T>
bool pointOnSegment(const Point<T> &p, const Line<T> &l) {
return cross(p - l.a, l.b - l.a) == 0 && std::min(l.a.x, l.b.x) <= p.x && p.x <= std::max(l.a.x, l.b.x)
&& std::min(l.a.y, l.b.y) <= p.y && p.y <= std::max(l.a.y, l.b.y);
}
// 点a是否在由p中的点组成的面中
// 是返回true 否返回false
template<class T>
bool pointInPolygon(const Point<T> &a, const std::vector<Point<T>> &p) {
int n = p.size();
for (int i = 0; i < n; i++) {
if (pointOnSegment(a, Line(p[i], p[(i + 1) % n]))) {
return true;
}
}
int t = 0;
for (int i = 0; i < n; i++) {
auto u = p[i];
auto v = p[(i + 1) % n];
if (u.x < a.x && v.x >= a.x && pointOnLineLeft(a, Line(v, u))) {
t ^= 1;
}
if (u.x >= a.x && v.x < a.x && pointOnLineLeft(a, Line(u, v))) {
t ^= 1;
}
}
return t == 1;
}
// 0 : not intersect(不相交)
// 1 : strictly intersect(严格相交)
// 2 : overlap(重叠)
// 3 : intersect at endpoint(在端点处相交)
// 线段相交
template<class T>
std::tuple<int, Point<T>, Point<T>> segmentIntersection(const Line<T> &l1, const Line<T> &l2) {
if (std::max(l1.a.x, l1.b.x) < std::min(l2.a.x, l2.b.x)) {
return {0, Point<T>(), Point<T>()};
}
if (std::min(l1.a.x, l1.b.x) > std::max(l2.a.x, l2.b.x)) {
return {0, Point<T>(), Point<T>()};
}
if (std::max(l1.a.y, l1.b.y) < std::min(l2.a.y, l2.b.y)) {
return {0, Point<T>(), Point<T>()};
}
if (std::min(l1.a.y, l1.b.y) > std::max(l2.a.y, l2.b.y)) {
return {0, Point<T>(), Point<T>()};
}
if (cross(l1.b - l1.a, l2.b - l2.a) == 0) {
if (cross(l1.b - l1.a, l2.a - l1.a) != 0) {
return {0, Point<T>(), Point<T>()};
} else {
auto maxx1 = std::max(l1.a.x, l1.b.x);
auto minx1 = std::min(l1.a.x, l1.b.x);
auto maxy1 = std::max(l1.a.y, l1.b.y);
auto miny1 = std::min(l1.a.y, l1.b.y);
auto maxx2 = std::max(l2.a.x, l2.b.x);
auto minx2 = std::min(l2.a.x, l2.b.x);
auto maxy2 = std::max(l2.a.y, l2.b.y);
auto miny2 = std::min(l2.a.y, l2.b.y);
Point<T> p1(std::max(minx1, minx2), std::max(miny1, miny2));
Point<T> p2(std::min(maxx1, maxx2), std::min(maxy1, maxy2));
if (!pointOnSegment(p1, l1)) {
std::swap(p1.y, p2.y);
}
if (p1 == p2) {
return {3, p1, p2};
} else {
return {2, p1, p2};
}
}
}
auto cp1 = cross(l2.a - l1.a, l2.b - l1.a);
auto cp2 = cross(l2.a - l1.b, l2.b - l1.b);
auto cp3 = cross(l1.a - l2.a, l1.b - l2.a);
auto cp4 = cross(l1.a - l2.b, l1.b - l2.b);
if ((cp1 > 0 && cp2 > 0) || (cp1 < 0 && cp2 < 0) || (cp3 > 0 && cp4 > 0) || (cp3 < 0 && cp4 < 0)) {
return {0, Point<T>(), Point<T>()};
}
Point p = lineIntersection(l1, l2);
if (cp1 != 0 && cp2 != 0 && cp3 != 0 && cp4 != 0) {
return {1, p, p};
} else {
return {3, p, p};
}
}
// 线段l1和l2的距离
template<class T>
double distanceSS(const Line<T> &l1, const Line<T> &l2) {
if (std::get<0>(segmentIntersection(l1, l2)) != 0) {
return 0.0;
}
return std::min({distancePS(l1.a, l2), distancePS(l1.b, l2), distancePS(l2.a, l1), distancePS(l2.b, l1)});
}
// 线段l是否在由p中的点组成的面中
template<class T>
bool segmentInPolygon(const Line<T> &l, const std::vector<Point<T>> &p) {
int n = p.size();
if (!pointInPolygon(l.a, p)) {
return false;
}
if (!pointInPolygon(l.b, p)) {
return false;
}
for (int i = 0; i < n; i++) {
auto u = p[i];
auto v = p[(i + 1) % n];
auto w = p[(i + 2) % n];
auto [t, p1, p2] = segmentIntersection(l, Line(u, v));
if (t == 1) {
return false;
}
if (t == 0) {
continue;
}
if (t == 2) {
if (pointOnSegment(v, l) && v != l.a && v != l.b) {
if (cross(v - u, w - v) > 0) {
return false;
}
}
} else {
if (p1 != u && p1 != v) {
if (pointOnLineLeft(l.a, Line(v, u))
|| pointOnLineLeft(l.b, Line(v, u))) {
return false;
}
} else if (p1 == v) {
if (l.a == v) {
if (pointOnLineLeft(u, l)) {
if (pointOnLineLeft(w, l)
&& pointOnLineLeft(w, Line(u, v))) {
return false;
}
} else {
if (pointOnLineLeft(w, l)
|| pointOnLineLeft(w, Line(u, v))) {
return false;
}
}
} else if (l.b == v) {
if (pointOnLineLeft(u, Line(l.b, l.a))) {
if (pointOnLineLeft(w, Line(l.b, l.a))
&& pointOnLineLeft(w, Line(u, v))) {
return false;
}
} else {
if (pointOnLineLeft(w, Line(l.b, l.a))
|| pointOnLineLeft(w, Line(u, v))) {
return false;
}
}
} else {
if (pointOnLineLeft(u, l)) {
if (pointOnLineLeft(w, Line(l.b, l.a))
|| pointOnLineLeft(w, Line(u, v))) {
return false;
}
} else {
if (pointOnLineLeft(w, l)
|| pointOnLineLeft(w, Line(u, v))) {
return false;
}
}
}
}
}
}
return true;
}
template<class T>
std::vector<Point<T>> hp(std::vector<Line<T>> lines) {
std::sort(lines.begin(), lines.end(), [&](auto l1, auto l2) {
auto d1 = l1.b - l1.a;
auto d2 = l2.b - l2.a;
if (sgn(d1) != sgn(d2)) {
return sgn(d1) == 1;
}
return cross(d1, d2) > 0;
});
std::deque<Line<T>> ls;
std::deque<Point<T>> ps;
for (auto l : lines) {
if (ls.empty()) {
ls.push_back(l);
continue;
}
while (!ps.empty() && !pointOnLineLeft(ps.back(), l)) {
ps.pop_back();
ls.pop_back();
}
while (!ps.empty() && !pointOnLineLeft(ps[0], l)) {
ps.pop_front();
ls.pop_front();
}
if (cross(l.b - l.a, ls.back().b - ls.back().a) == 0) {
if (dot(l.b - l.a, ls.back().b - ls.back().a) > 0) {
if (!pointOnLineLeft(ls.back().a, l)) {
assert(ls.size() == 1);
ls[0] = l;
}
continue;
}
return {};
}
ps.push_back(lineIntersection(ls.back(), l));
ls.push_back(l);
}
while (!ps.empty() && !pointOnLineLeft(ps.back(), ls[0])) {
ps.pop_back();
ls.pop_back();
}
if (ls.size() <= 2) {
return {};
}
ps.push_back(lineIntersection(ls[0], ls.back()));
return std::vector(ps.begin(), ps.end());
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
i64 n, k, b;
std::cin >> n >> k >> b;
Line<i64> ly;
ly.a.x = -10000000;
ly.a.y = -10000000 * k + b;
ly.b.x = 10000000;
ly.b.y = 10000000 * k + b;
std::set<int> st1, st2, st3;
for(int i = 0; i < 2 * n; i++) {
Point<i64> p;
std::cin >> p.x >> p.y;
if(p.y == k * p.x + b) {
st3.insert(i);
continue;
}
if(pointOnLineLeft(p, ly)) {
st1.insert(i);
} else {
st2.insert(i);
}
}
int n1 = st1.size(), n2 = st2.size(), n3 = st3.size();
int gap = std::abs(n1 - n2);
// std::cout << st1.size() << " " << st2.size() << " " << st3.size() << "\n";
std::cout << std::min(n1, n2) + std::min(gap, n3) + std::max(0, n3 - gap) / 2 << "\n";
while(st3.size()) {
if(st1.size() == 0 && st2.size() == 0) {
break;
}
if(st1.size() > st2.size()) {
std::cout << *st1.begin() + 1 << " " << *st3.begin() + 1 << " Y\n";
st1.erase(st1.begin());
st3.erase(st3.begin());
} else {
std::cout << *st2.begin() + 1 << " " << *st3.begin() + 1 << " Y\n";
st2.erase(st2.begin());
st3.erase(st3.begin());
}
}
while(st1.size() && st2.size()) {
std::cout << *st1.begin() + 1 << " " << *st2.begin() + 1 << " Y\n";
st1.erase(st1.begin());
st2.erase(st2.begin());
}
while(st1.size()) {
std::cout << *st1.begin() + 1 << " ";
st1.erase(st1.begin());
std::cout << *st1.begin() + 1 << " N\n";
st1.erase(st1.begin());
}
while(st2.size()) {
std::cout << *st2.begin() + 1 << " ";
st2.erase(st2.begin());
std::cout << *st2.begin() + 1 << " N\n";
st2.erase(st2.begin());
}
while(st3.size()) {
std::cout << *st3.begin() + 1 << " ";
st3.erase(st3.begin());
std::cout << *st3.begin() + 1 << " Y\n";
st3.erase(st3.begin());
}
return 0;
}
F - 小红的数组操作
原题
小红拿到了 n n n 个数组,她有以下两种操作:
1.输入 1 i j x 1\space i \space j \space x 1 i j x将第 i i i 个数组的第 j j j 个元素修改为 x x x;
2.输入 2 i 2 \space i 2 i查询前 i i i 个数组的最小值。
输入
第一行输入一个正整数 n ( 1 ≤ n ≤ 1 0 5 ) n(1 \le n \le 10^5) n(1≤n≤105),代表数组的个数。
接下来 n n n 行,每行先输入一个正整数 m i ( 1 ≤ m i ≤ 1 0 5 ) m_{i}(1 \le m_{i} \le 10^5) mi(1≤mi≤105),代表数组的长度,接下来输入 m i m_{i} mi个整数, a i j ( 1 ≤ a i j ≤ 1 0 9 ) a_{ij}(1 \le a_{ij} \le 10^9) aij(1≤aij≤109)表示数组的元素。
接下来输入一个正整数 q ( 1 ≤ q ≤ 1 0 5 ) q(1 \le q \le 10^5) q(1≤q≤105),代表操作的次数。
接下来 q q q 行,每行先输入一个正整数 t ( 1 ≤ t ≤ 2 ) t(1 \le t \le 2) t(1≤t≤2)表示操作的类型。
如果 t = 1 t = 1 t=1。则接下来输入三个正整数 i , j , x ( 1 ≤ i ≤ n ; 1 ≤ j ≤ m ; 1 ≤ x ≤ 1 0 9 ) i, j, x(1 \le i \le n;1 \le j \le m;1 \le x \le 10^9) i,j,x(1≤i≤n;1≤j≤m;1≤x≤109),表示将第 i i i个数组的第 j j j个元素修改为 x x x。
如果 t = 2 t = 2 t=2,则接下来输入一个正整数 i ( 1 ≤ i ≤ n ) i(1 \le i \le n) i(1≤i≤n),表示查询前 i i i 个数组的最小值
保证至少有一个查询操作,且 ∑ i = 1 n m i ≤ 1 0 5 \sum_{i = 1}^n m_{i} \le 10^5 ∑i=1nmi≤105
输出
对于每个查询操作,输出一个整数,表示查询的结果。
测试样例
input1
4
3 1 2 3
3 4 5 6
4 7 8 9 10
2 1 2
5
2 2
1 1 1 10
2 3
1 1 2 11
2 2
output1
1
2
3
分析
- 这题其实是线段树的板子题,只不过修改的操作需要进行处理,具体处理方式见代码
#include<bits/stdc++.h>
#define all(a) a.begin(), a.end()
using i32 = int;
using u32 = unsigned int;
using i64 = long long;
using u64 = unsigned long long;
template<class Info>
struct SegmentTree {
int n;
std::vector<Info> info;
SegmentTree() : n(0) {}
SegmentTree(int n_, Info v_ = Info()) {
init(n_, v_);
}
template<class T>
SegmentTree(std::vector<T> init_) {
init(init_);
}
void init(int n_, Info v_ = Info()) {
init(std::vector(n_, v_));
}
template<class T>
void init(std::vector<T> init_) {
n = init_.size();
info.assign(4 << std::__lg(n), Info());
std::function<void(int, int, int)> build = [&](int p, int l, int r) {
if (r - l == 1) {
info[p] = init_[l];
return;
}
int m = (l + r) / 2;
build(2 * p, l, m);
build(2 * p + 1, m, r);
pull(p);
};
build(1, 0, n);
}
void pull(int p) {
info[p] = info[2 * p] + info[2 * p + 1];
}
void modify(int p, int l, int r, int x, const Info &v) {
if (r - l == 1) {
info[p] = v;
return;
}
int m = (l + r) / 2;
if (x < m) {
modify(2 * p, l, m, x, v);
} else {
modify(2 * p + 1, m, r, x, v);
}
pull(p);
}
void modify(int p, const Info &v) {
modify(1, 0, n, p, v);
}
Info rangeQuery(int p, int l, int r, int x, int y) {
if (l >= y || r <= x) {
return Info();
}
if (l >= x && r <= y) {
return info[p];
}
int m = (l + r) / 2;
return rangeQuery(2 * p, l, m, x, y) + rangeQuery(2 * p + 1, m, r, x, y);
}
Info rangeQuery(int l, int r) {
return rangeQuery(1, 0, n, l, r);
}
template<class F>
int findFirst(int p, int l, int r, int x, int y, F pred) {
if (l >= y || r <= x || !pred(info[p])) {
return -1;
}
if (r - l == 1) {
return l;
}
int m = (l + r) / 2;
int res = findFirst(2 * p, l, m, x, y, pred);
if (res == -1) {
res = findFirst(2 * p + 1, m, r, x, y, pred);
}
return res;
}
template<class F>
int findFirst(int l, int r, F pred) {
return findFirst(1, 0, n, l, r, pred);
}
template<class F>
int findLast(int p, int l, int r, int x, int y, F pred) {
if (l >= y || r <= x || !pred(info[p])) {
return -1;
}
if (r - l == 1) {
return l;
}
int m = (l + r) / 2;
int res = findLast(2 * p + 1, m, r, x, y, pred);
if (res == -1) {
res = findLast(2 * p, l, m, x, y, pred);
}
return res;
}
template<class F>
int findLast(int l, int r, F pred) {
return findLast(1, 0, n, l, r, pred);
}
};
const int inf = 1E9 + 7;
struct Info {
int ans = inf;
};
Info operator+(Info a, Info b) {
Info c{};
c.ans = std::min(a.ans, b.ans);
return c;
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
int n;
std::cin >> n;
std::multiset<int> min[n];
std::vector<std::vector<int>> s(n);
for(int i = 0; i < n; i++) {
int m;
std::cin >> m;
for(int j = 0; j < m; j++) {
int k;
std::cin >> k;
s[i].push_back(k);
min[i].insert(k);
}
}
SegmentTree<Info> seg(n);
for(int i = 0; i < n; i++) {
seg.modify(i, {*min[i].begin()});
}
int q;
std::cin >> q;
for(int i = 0; i < q; i++) {
int t;
std::cin >> t;
if(t == 1) {
int a, b, x;
std::cin >> a >> b >> x;
a--;
b--;
min[a].erase(s[a][b]);
s[a][b] = x;
min[a].insert(x);
seg.modify(a, {*min[a].begin()});
} else {
int k;
std::cin >> k;
std::cout << seg.rangeQuery(0, k).ans << "\n";
}
}
return 0;
}
G - 小红的双排列构造
原题
小红希望你构造一个长度为 2 × n 2 \times n 2×n 的双排列,满足:恰好有 k k k 个长度为 n n n 的区间为排列。你能帮帮她吗?
长度为 n 的排列是由 1 到 n 中的 n 个不同整数、按任意顺序组成的数组,其中每个整数恰好出现一次。例如,[2,3,1,5,4] 是一个排列,但 [1,2,2] 不是一个排列(数组中的 2 出现了两次),[1,3,4] 也不是一个排列(长度为 3 但数组中有 4)。
定义双排列为两个长度为 𝑛 的排列打乱顺序后得到的数组,或者说是由 1 到 𝑛 中的 𝑛 个不同整数、按任意顺序组成的数组,其中每个整数恰好出现两次。
输入
在一行上输入两个整数 n , k ( 1 ≤ n ≤ 1 0 5 ; 0 ≤ k ≤ n + 1 ) n,k(1 \le n \le 10^5; 0 \le k \le n + 1) n,k(1≤n≤105;0≤k≤n+1) 代表要求构造的双排列长度及限制。
输出
如果无法构造出符合要求的双排列,直接在一行上输出 −1 ;否则,在一行上输出 2 × n 2 \times n 2×n 个整数,代表构造的双排列。
如果存在多个解决方案,您可以输出任意一个,系统会自动判定是否正确。注意,自测运行功能可能因此返回错误结果,请自行检查答案正确性。
测试样例
input1
3 4
output1
1 2 3 1 2 3
input2
4 1
outpu2
3 4 3 1 2 2 4 1
分析
- 分情况讨论
1.当 k = 0,那么直接输出 1 1 2 2 3 3 …即可,需要注意 n
≤
2
\le 2
≤2时是不存在
k
=
0
k = 0
k=0的情况
2. 当 k = 1,那么可以保留一个排列,拆开另一个排列,这样可以保证只有一个,特判n = 1 的情况
3. 当k > 1,先保留一个排列 1 2 3 4 …然后再在后面插入尾插排列的前 k - 1个数,再打乱剩下的数即可
#include<bits/stdc++.h>
#define all(a) a.begin(), a.end()
using i32 = int;
using u32 = unsigned int;
using i64 = long long;
using u64 = unsigned long long;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
int n, k;
std::cin >> n >> k;
if(k == 0) {
if(n <= 2) {
std::cout << -1;
} else {
for(int i = 1; i <= n; i++) {
std::cout << i << " " << i << " ";
}
}
} else if(k == 1) {
if(n == 1) {
std::cout << -1;
} else {
std::vector<int> ans;
ans.push_back(1);
for(int i = 1; i <= n; i++) {
ans.push_back(i);
}
ans.push_back(n);
for(int i = 2; i < n; i++) {
ans.push_back(i);
}
for(auto x : ans) {
std::cout << x << " ";
}
}
} else {
std::vector<int> ans;
for(int i = 1; i <= n; i++) {
ans.push_back(i);
}
for (int i = 1; i <= k - 2; i++) {
ans.push_back(i);
}
for (int i = n; i > k - 2 && i; i--) {
ans.push_back(i);
}
for(auto x : ans) {
std::cout << x << " ";
}
}
return 0;
}