【CCPC】CCPC 2023 Shenzhen Site A
#构造 #分治 #贪心
题目描述
A good problem should have a concise statement.
You are given an array
a
a
a of length
n
n
n, initially filled with zeros, and another array
b
b
b of length
n
n
n. Your goal
is to transform array
a
a
a into array
b
b
b. You can perform the following two types of operations:
•
1
x
:
1 \ x:
1 x: Add
1
1
1 to all elements in a that are equal to
x
.
x.
x.
•
2
x
:
2 \ x:
2 x: Add
1
1
1 to the element in a at index
x
.
x.
x.
You can perform no more than
20000
20 000
20000 operations.
输入格式
The first line contains a positive integer
n
(
1
≤
n
≤
1000
)
.
n (1 ≤ n ≤ 1000).
n(1≤n≤1000).
The second line contains
n
n
n non-negative integers representing the array
b
(
0
≤
b
i
≤
n
)
b (0 ≤ bi ≤ n)
b(0≤bi≤n)
输出格式
The first line should contain an integer k, representing the number of operations.
The following
k
k
k lines should each contain two integers
1
1
1
x
x
x or
2
x
2 \ x
2 x, representing an operation. For the
operation type
1
x
1\ x
1 x, you must ensure that
0
≤
x
≤
n
.
0 ≤ x ≤ n.
0≤x≤n. For the operation type
2
x
2\ x
2 x, you must ensure that
1
≤
x
≤
n
.
1 ≤ x ≤ n.
1≤x≤n.
样例 #1
样例输入 #1
4
2 4 3 1
样例输出 #1
8
2 1
2 2
2 3
1 1
2 4
2 2
2 3
2 2
解法
首先,观察到 n ≤ 1000 n\leq 1000 n≤1000,操作次数在 2 e 4 2e4 2e4以内,大概是 n l o g 2 nlog_2 nlog2次数级别的,因此我们需要考虑如何得到这个 l o g 2 n log_2n log2n。
首先对于 2 2 2操作,一次只能操作一个下标,而对于 1 1 1操作,可以操作多个数,因此我们要尽量减少 2 2 2操作。
考虑如果尽量多的 1 1 1操作:
初始数组全为
0
0
0,即:
[
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
]
[0,0,0,0,0,0,0,0]
[0,0,0,0,0,0,0,0]
假设目标数组为
[
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
]
[1,2,3,4,5,6,7,8]
[1,2,3,4,5,6,7,8]
那么我们其实可以这样操作,先推平右半部分为
[
5
,
5
,
5
,
5
]
[5,5,5,5]
[5,5,5,5],具体而言就是:
1. 1. 1.进行 4 4 4个 2 2 2操作变为: [ 1 , 1 , 1 , 1 ] [1,1,1,1] [1,1,1,1]
2. 2. 2.进行 4 4 4个 1 1 1操作变为 [ 5 , 5 , 5 , 5 , 5 ] [5,5,5,5,5] [5,5,5,5,5]
现在数组变为了
[
0
,
0
,
0
,
0
,
5
,
5
,
5
,
5
]
[0,0,0,0,5,5,5,5]
[0,0,0,0,5,5,5,5]
实际上右边部分仍然全部相等,我们依旧可以当做全为 0 0 0的情况来讨论,依旧推平右半部分为: [ 7 , 7 ] [7,7] [7,7]
同样是通过
2
2
2次
2
2
2操作,
2
2
2次
1
1
1操作实现的,现在数组变为了:
[
0
,
0
,
0
,
0
,
5
,
5
,
7
,
7
]
[0,0,0,0,5,5,7,7]
[0,0,0,0,5,5,7,7]
那么这样实际上就是一种递归分治,因为每次的子问题都相同,就像下图所示:
![[Pasted image 20241011124648.png|700]]
由于值域只有 n ≤ 1000 n \leq 1000 n≤1000,因此我们可以直接开个桶来存值的下标。
这样分治的操作次数在 n l o g 2 n nlog_2n nlog2n左右。
代码
void solve() {
int n;
std::cin >> n;
std::vector<std::vector<int>>a(n + 1);
for (int i = 1; i <= n; ++i) {
int x;
std::cin >> x;
a[x].emplace_back(i);
}
std::vector<pii>res;
auto dfs = [&](auto&& self, int l, int r,int now)->void {
if (l > r) return;
int mid = l + r >> 1;
if (l == r) {
for (auto& idx : a[l]) {
for (int i = l + 1; i <= now; ++i) {
res.push_back({ 2,idx });
}
}
return;
}
if (mid + 1 <= r) {
int p = now;
bool ok = false;
for (int i = mid + 1; i <= r; ++i) { //整体+1
for (auto& idx : a[i]) {
res.push_back({ 2,idx });
ok = true;
}
}
p += ok;
if (ok) {
while (p < mid + 1) {
res.push_back({ 1,p });
p++;
}
}
self(self, mid + 1, r, p);
}
if (l <= mid) {
self(self, l, mid,now);
}
};
dfs(dfs, 0, n,0);
std::cout << res.size() << "\n";
for (auto& [x, y] : res) {
std::cout << x << " " << y << "\n";
}
}
signed main() {
std::ios::sync_with_stdio(0);
std::cin.tie(0);
std::cout.tie(0);
int t = 1;
//std::cin >> t;
while (t--) {
solve();
}
};
原文地址:https://blog.csdn.net/Antonio915/article/details/142851204
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!