题解 - Codeforces Round #829 (Div. 2)

比赛链接

A - Technical Support

You work in the quality control department of technical support for a large company. Your job is to make sure all client issues have been resolved.

Today you need to check a copy of a dialog between a client and a technical support manager. According to the rules of work, each message of the client must be followed by one or several messages, which are the answer of a support manager. However, sometimes clients ask questions so quickly that some of the manager's answers to old questions appear after the client has asked some new questions.

Due to the privacy policy, the full text of messages is not available to you, only the order of messages is visible, as well as the type of each message: a customer question or a response from the technical support manager. It is guaranteed that the dialog begins with the question of the client.

You have to determine, if this dialog may correspond to the rules of work described above, or the rules are certainly breached.

Input

Each test contains multiple test cases. The first line contains the number of test cases \(t\) (\(1 \le t \le 500\)). Description of the test cases follows.

The first line of each test case contains one integer \(n\) (\(1 \le n \le 100\)) — the total number of messages in the dialog.

The second line of each test case consists of \(n\) characters "Q" and "A", describing types of messages in the dialog in chronological order. Character "Q" denotes the message with client question, and character "A" — the message with technical support manager answer. It is guaranteed that the first character in the line equals to "Q".

Output

For each test case print "Yes" (without quotes) if dialog may correspond to the rules of work, or "No" (without quotes) otherwise.

Example

input

1
2
3
4
5
6
7
8
9
10
11
5
4
QQAA
4
QQAQ
3
QAA
1
Q
14
QAQQAQAAQQQAAA

output

1
2
3
4
5
Yes
No
Yes
No
Yes

Note

In the first test case the two questions from the client are followed with two specialist's answers. So this dialog may correspond to the rules of work.

In the second test case one of the first two questions was not answered.

In the third test case the technical support manager sent two messaged as the answer to the only message of the client.

思路与做法

没啥好说的,扫一遍就行

代码参考

Show code

CodeForces_1754Aview raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
/*
* @Author: Tifa
* @Description: From <https://github.com/Tiphereth-A/CP-archives>
* !!! ATTENEION: All the context below is licensed under a
* GNU Affero General Public License, Version 3.
* See <https://www.gnu.org/licenses/agpl-3.0.txt>.
*/
#include <bits/stdc++.h>
struct CustomHash {
static uint64_t splitmix64(uint64_t x) {
x += 0x9e3779b97f4a7c15;
x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
return x ^ (x >> 31);
}
size_t operator()(uint64_t x) const {
static const uint64_t FIXED_RANDOM =
std::chrono::steady_clock::now().time_since_epoch().count();
return splitmix64(x + FIXED_RANDOM);
}
};
#define run_exec_(expressions, post_process) \
{ \
expressions; \
post_process; \
}
#define run_continue_(expressions) run_exec_(expressions, continue)
#define read_var_(type, name) \
type name; \
std::cin >> name
template <class Tp>
constexpr auto chkmin(Tp &a, Tp b) -> bool {
return b < a ? a = b, true : false;
}
template <class Tp>
constexpr auto chkmax(Tp &a, Tp b) -> bool {
return a < b ? a = b, true : false;
}
template <class Tp>
constexpr auto ispow2(Tp i) -> bool {
return i && (i & -i) == i;
}
#define TPL_SIZE_(Tuple) std::tuple_size_v<std::remove_reference_t<Tuple>>
namespace tuple_detail_ {
template <std::size_t Begin, class Tuple, std::size_t... Is>
constexpr auto subtuple_impl_(Tuple &&t, std::index_sequence<Is...>) {
return std::make_tuple(std::get<Is + Begin>(t)...);
}
template <class Tuple, class BinOp, std::size_t... Is>
constexpr auto
apply2_impl_(BinOp &&f, Tuple &&lhs, Tuple &&rhs, std::index_sequence<Is...>) {
return std::make_tuple(
std::forward<BinOp>(f)(std::get<Is>(lhs), std::get<Is>(rhs))...);
}
} // namespace tuple_detail_
template <std::size_t Begin, std::size_t Len, class Tuple>
constexpr auto subtuple(Tuple &&t) {
static_assert(Begin <= TPL_SIZE_(Tuple) && Len <= TPL_SIZE_(Tuple) &&
Begin + Len <= TPL_SIZE_(Tuple),
"Out of range");
return tuple_detail_::subtuple_impl_<Begin>(t,
std::make_index_sequence<Len>());
}
template <std::size_t Pos, class Tp, class Tuple>
constexpr auto tuple_push(Tp &&v, Tuple &&t) {
static_assert(TPL_SIZE_(Tuple) > 0, "Pop from empty tuple");
return std::tuple_cat(subtuple<0, Pos>(t),
std::make_tuple(v),
subtuple<Pos, TPL_SIZE_(Tuple) - Pos>(t));
}
template <class Tp, class Tuple>
constexpr auto tuple_push_front(Tp &&v, Tuple &&t) {
return tuple_push<0>(v, t);
}
template <class Tp, class Tuple>
constexpr auto tuple_push_back(Tp &&v, Tuple &&t) {
return tuple_push<TPL_SIZE_(Tuple)>(v, t);
}
template <std::size_t Pos, class Tuple>
constexpr auto tuple_pop(Tuple &&t) {
static_assert(TPL_SIZE_(Tuple) > 0, "Pop from empty tuple");
return std::tuple_cat(subtuple<0, Pos>(t),
subtuple<Pos + 1, TPL_SIZE_(Tuple) - Pos - 1>(t));
}
template <class Tuple>
constexpr auto tuple_pop_front(Tuple &&t) {
return tuple_pop<0>(t);
}
template <class Tuple>
constexpr auto tuple_pop_back(Tuple &&t) {
return tuple_pop<TPL_SIZE_(Tuple) - 1>(t);
}
template <class Tuple, class BinOp>
constexpr auto apply2(BinOp &&f, Tuple &&lhs, Tuple &&rhs) {
return tuple_detail_::apply2_impl_(
f, lhs, rhs, std::make_index_sequence<TPL_SIZE_(Tuple)>());
}
#define OO_PTEQ_(op) \
template <class Tp, class Up> \
constexpr auto operator op(std::pair<Tp, Up> lhs, \
const std::pair<Tp, Up> &rhs) { \
return {lhs.first op rhs.first, lhs.second op rhs.second}; \
} \
template <class... Ts> \
constexpr auto operator op(std::tuple<Ts...> const &lhs, \
std::tuple<Ts...> const &rhs) { \
return apply2([](auto &&l, auto &&r) { return l op r; }, lhs, rhs); \
} \
template <class Tp, class Up> \
constexpr std::pair<Tp, Up> &operator op##=(std::pair<Tp, Up> &lhs, \
const std::pair<Tp, Up> &rhs) { \
lhs.first op## = rhs.first; \
lhs.second op## = rhs.second; \
return lhs; \
} \
template <class... Ts> \
constexpr auto operator op##=(std::tuple<Ts...> &lhs, \
const std::tuple<Ts...> &rhs) { \
return lhs = lhs op rhs; \
}
OO_PTEQ_(+)
OO_PTEQ_(-)
OO_PTEQ_(*)
OO_PTEQ_(/)
OO_PTEQ_(%)
OO_PTEQ_(&)
OO_PTEQ_(|)
OO_PTEQ_(^)
OO_PTEQ_(<<)
OO_PTEQ_(>>)
#undef OO_PTEQ_
#undef TPL_SIZE_
template <class Tp, class Up>
std::istream &operator>>(std::istream &is, std::pair<Tp, Up> &p) {
return is >> p.first >> p.second;
}
template <class Tp, class Up>
std::ostream &operator<<(std::ostream &os, const std::pair<Tp, Up> &p) {
return os << p.first << ' ' << p.second;
}
template <typename... Ts>
std::istream &operator>>(std::istream &is, std::tuple<Ts...> &p) {
std::apply([&](Ts &...targs) { ((is >> targs), ...); }, p);
return is;
}
template <typename... Ts>
std::ostream &operator<<(std::ostream &os, const std::tuple<Ts...> &p) {
std::apply(
[&](Ts const &...targs) {
std::size_t n{0};
((os << targs << (++n != sizeof...(Ts) ? " " : "")), ...);
},
p);
return os;
}
template <class Ch,
class Tr,
class Ct,
std::enable_if_t<std::is_same_v<decltype(std::declval<Ct>().begin()),
typename Ct::iterator> &&
std::is_same_v<decltype(std::declval<Ct>().end()),
typename Ct::iterator>> * = nullptr>
std::basic_ostream<Ch, Tr> &operator<<(std::basic_ostream<Ch, Tr> &os,
const Ct &x) {
if (x.begin() == x.end()) return os;
for (auto it = x.begin(); it != x.end() - 1; ++it) os << *it << ' ';
os << x.back();
return os;
}
const std::string RES_Yn[2] = {"No", "Yes"};
using namespace std;
auto solve([[maybe_unused]] int t_ = 0) -> void {
read_var_(int, n);
read_var_(string, s);
int cntq = 0;
for (auto &&ch : s) {
if (ch == 'Q') run_continue_(++cntq);
if (cntq) --cntq;
}
cout << RES_Yn[!cntq] << '\n';
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int i_ = 0;
int t_ = 0;
std::cin >> t_;
for (i_ = 0; i_ < t_; ++i_) solve(i_);
return 0;
}

B - Kevin and Permutation

For his birthday, Kevin received the set of pairwise distinct numbers \(1, 2, 3, \ldots, n\) as a gift.

He is going to arrange these numbers in a way such that the minimum absolute difference between two consecutive numbers be maximum possible. More formally, if he arranges numbers in order \(p_1, p_2, \ldots, p_n\), he wants to maximize the value

\[ \min \limits_{i=1}^{n - 1} \lvert p_{i + 1} - p_i \rvert, \]

where \(|x|\) denotes the absolute value of \(x\).

Help Kevin to do that.

Input

Each test consists of multiple test cases. The first line contains a single integer \(t\) (\(1 \le t \le 100\)) — the number of test cases. Description of the test cases follows.

The only line of each test case contains an integer \(n\) (\(2 \le n \leq 1\,000\)) — the size of the set.

Output

For each test case print a single line containing \(n\) distinct integers \(p_1, p_2, \ldots, p_n\) (\(1 \le p_i \le n\)) describing the arrangement that maximizes the minimum absolute difference of consecutive elements.

Formally, you have to print a permutation \(p\) which maximizes the value \(\min \limits_{i=1}^{n - 1} \lvert p_{i + 1} - p_i \rvert\).

If there are multiple optimal solutions, print any of them.

Example

input

1
2
3
2
4
3

output

1
2
2 4 1 3
1 2 3

Note

In the first test case the minimum absolute difference of consecutive elements equals \(\min \{\lvert 4 - 2 \rvert, \lvert 1 - 4 \rvert, \lvert 3 - 1 \rvert \} = \min \{2, 3, 2\} = 2\). It's easy to prove that this answer is optimal.

In the second test case each permutation of numbers \(1, 2, 3\) is an optimal answer. The minimum absolute difference of consecutive elements equals to \(1\).

思路与做法

显然差值最大为 \(\lfloor\frac{p}{2}\rfloor\), 构造方式也不难想

代码参考

Show code

CodeForces_1754Bview raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
/*
* @Author: Tifa
* @Description: From <https://github.com/Tiphereth-A/CP-archives>
* !!! ATTENEION: All the context below is licensed under a
* GNU Affero General Public License, Version 3.
* See <https://www.gnu.org/licenses/agpl-3.0.txt>.
*/
#include <bits/stdc++.h>
template <class Tp>
using vc = std::vector<Tp>;
struct CustomHash {
static uint64_t splitmix64(uint64_t x) {
x += 0x9e3779b97f4a7c15;
x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
return x ^ (x >> 31);
}
size_t operator()(uint64_t x) const {
static const uint64_t FIXED_RANDOM =
std::chrono::steady_clock::now().time_since_epoch().count();
return splitmix64(x + FIXED_RANDOM);
}
};
#define rfor_(i, r, l, vars...) \
for (std::make_signed_t<decltype(r - l)> i = (r), i##end = (l), ##vars; \
i >= i##end; \
--i)
#define read_var_(type, name) \
type name; \
std::cin >> name
template <class Tp>
constexpr auto chkmin(Tp &a, Tp b) -> bool {
return b < a ? a = b, true : false;
}
template <class Tp>
constexpr auto chkmax(Tp &a, Tp b) -> bool {
return a < b ? a = b, true : false;
}
template <class Tp>
constexpr auto ispow2(Tp i) -> bool {
return i && (i & -i) == i;
}
#define TPL_SIZE_(Tuple) std::tuple_size_v<std::remove_reference_t<Tuple>>
namespace tuple_detail_ {
template <std::size_t Begin, class Tuple, std::size_t... Is>
constexpr auto subtuple_impl_(Tuple &&t, std::index_sequence<Is...>) {
return std::make_tuple(std::get<Is + Begin>(t)...);
}
template <class Tuple, class BinOp, std::size_t... Is>
constexpr auto
apply2_impl_(BinOp &&f, Tuple &&lhs, Tuple &&rhs, std::index_sequence<Is...>) {
return std::make_tuple(
std::forward<BinOp>(f)(std::get<Is>(lhs), std::get<Is>(rhs))...);
}
} // namespace tuple_detail_
template <std::size_t Begin, std::size_t Len, class Tuple>
constexpr auto subtuple(Tuple &&t) {
static_assert(Begin <= TPL_SIZE_(Tuple) && Len <= TPL_SIZE_(Tuple) &&
Begin + Len <= TPL_SIZE_(Tuple),
"Out of range");
return tuple_detail_::subtuple_impl_<Begin>(t,
std::make_index_sequence<Len>());
}
template <std::size_t Pos, class Tp, class Tuple>
constexpr auto tuple_push(Tp &&v, Tuple &&t) {
static_assert(TPL_SIZE_(Tuple) > 0, "Pop from empty tuple");
return std::tuple_cat(subtuple<0, Pos>(t),
std::make_tuple(v),
subtuple<Pos, TPL_SIZE_(Tuple) - Pos>(t));
}
template <class Tp, class Tuple>
constexpr auto tuple_push_front(Tp &&v, Tuple &&t) {
return tuple_push<0>(v, t);
}
template <class Tp, class Tuple>
constexpr auto tuple_push_back(Tp &&v, Tuple &&t) {
return tuple_push<TPL_SIZE_(Tuple)>(v, t);
}
template <std::size_t Pos, class Tuple>
constexpr auto tuple_pop(Tuple &&t) {
static_assert(TPL_SIZE_(Tuple) > 0, "Pop from empty tuple");
return std::tuple_cat(subtuple<0, Pos>(t),
subtuple<Pos + 1, TPL_SIZE_(Tuple) - Pos - 1>(t));
}
template <class Tuple>
constexpr auto tuple_pop_front(Tuple &&t) {
return tuple_pop<0>(t);
}
template <class Tuple>
constexpr auto tuple_pop_back(Tuple &&t) {
return tuple_pop<TPL_SIZE_(Tuple) - 1>(t);
}
template <class Tuple, class BinOp>
constexpr auto apply2(BinOp &&f, Tuple &&lhs, Tuple &&rhs) {
return tuple_detail_::apply2_impl_(
f, lhs, rhs, std::make_index_sequence<TPL_SIZE_(Tuple)>());
}
#define OO_PTEQ_(op) \
template <class Tp, class Up> \
constexpr auto operator op(std::pair<Tp, Up> lhs, \
const std::pair<Tp, Up> &rhs) { \
return {lhs.first op rhs.first, lhs.second op rhs.second}; \
} \
template <class... Ts> \
constexpr auto operator op(std::tuple<Ts...> const &lhs, \
std::tuple<Ts...> const &rhs) { \
return apply2([](auto &&l, auto &&r) { return l op r; }, lhs, rhs); \
} \
template <class Tp, class Up> \
constexpr std::pair<Tp, Up> &operator op##=(std::pair<Tp, Up> &lhs, \
const std::pair<Tp, Up> &rhs) { \
lhs.first op## = rhs.first; \
lhs.second op## = rhs.second; \
return lhs; \
} \
template <class... Ts> \
constexpr auto operator op##=(std::tuple<Ts...> &lhs, \
const std::tuple<Ts...> &rhs) { \
return lhs = lhs op rhs; \
}
OO_PTEQ_(+)
OO_PTEQ_(-)
OO_PTEQ_(*)
OO_PTEQ_(/)
OO_PTEQ_(%)
OO_PTEQ_(&)
OO_PTEQ_(|)
OO_PTEQ_(^)
OO_PTEQ_(<<)
OO_PTEQ_(>>)
#undef OO_PTEQ_
#undef TPL_SIZE_
template <class Tp, class Up>
std::istream &operator>>(std::istream &is, std::pair<Tp, Up> &p) {
return is >> p.first >> p.second;
}
template <class Tp, class Up>
std::ostream &operator<<(std::ostream &os, const std::pair<Tp, Up> &p) {
return os << p.first << ' ' << p.second;
}
template <typename... Ts>
std::istream &operator>>(std::istream &is, std::tuple<Ts...> &p) {
std::apply([&](Ts &...targs) { ((is >> targs), ...); }, p);
return is;
}
template <typename... Ts>
std::ostream &operator<<(std::ostream &os, const std::tuple<Ts...> &p) {
std::apply(
[&](Ts const &...targs) {
std::size_t n{0};
((os << targs << (++n != sizeof...(Ts) ? " " : "")), ...);
},
p);
return os;
}
template <class Ch,
class Tr,
class Ct,
std::enable_if_t<std::is_same_v<decltype(std::declval<Ct>().begin()),
typename Ct::iterator> &&
std::is_same_v<decltype(std::declval<Ct>().end()),
typename Ct::iterator>> * = nullptr>
std::basic_ostream<Ch, Tr> &operator<<(std::basic_ostream<Ch, Tr> &os,
const Ct &x) {
if (x.begin() == x.end()) return os;
for (auto it = x.begin(); it != x.end() - 1; ++it) os << *it << ' ';
os << x.back();
return os;
}
using namespace std;
auto solve([[maybe_unused]] int t_ = 0) -> void {
read_var_(int, n);
vc<int> ans;
ans.reserve(n);
rfor_(i, n / 2, 1) {
ans.push_back(i);
ans.push_back(i + n / 2);
}
if (n & 1) ans.push_back(n);
cout << ans << '\n';
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int i_ = 0;
int t_ = 0;
std::cin >> t_;
for (i_ = 0; i_ < t_; ++i_) solve(i_);
return 0;
}

C1 - Make Nonzero Sum (easy version)

This is the easy version of the problem. The difference is that in this version the array can not contain zeros. You can make hacks only if both versions of the problem are solved.

You are given an array \([a_1, a_2, \ldots a_n]\) consisting of integers \(-1\) and \(1\). You have to build a partition of this array into the set of segments \([l_1, r_1], [l_2, r_2], \ldots, [l_k, r_k]\) with the following property:

  • Denote the alternating sum of all elements of the \(i\)-th segment as \(s_i\): \(s_i\) = \(a_{l_i} - a_{l_i+1} + a_{l_i+2} - a_{l_i+3} + \ldots \pm a_{r_i}\). For example, the alternating sum of elements of segment \([2, 4]\) in array \([1, 0, -1, 1, 1]\) equals to \(0 - (-1) + 1 = 2\).
  • The sum of \(s_i\) over all segments of partition should be equal to zero.

Note that each \(s_i\) does not have to be equal to zero, this property is about sum of \(s_i\) over all segments of partition.

The set of segments \([l_1, r_1], [l_2, r_2], \ldots, [l_k, r_k]\) is called a partition of the array \(a\) of length \(n\) if \(1 = l_1 \le r_1, l_2 \le r_2, \ldots, l_k \le r_k = n\) and \(r_i + 1 = l_{i+1}\) for all \(i = 1, 2, \ldots k-1\). In other words, each element of the array must belong to exactly one segment.

You have to build a partition of the given array with properties described above or determine that such partition does not exist.

Note that it is not required to minimize the number of segments in the partition.

Input

Each test contains multiple test cases. The first line contains the number of test cases \(t\) (\(1 \le t \le 10\,000\)). Description of the test cases follows.

The first line of each test case contains an integer \(n\) (\(1 \le n \le 200\,000\)) — the length of the array \(a\).

The second line of each test case contains \(n\) integers \(a_1, a_2, \ldots, a_n\) (\(a_i\) is \(-1\) or \(1\)) — the elements of the given array.

It's guaranteed that the sum of \(n\) over all test cases does not exceed \(200\,000\).

Output

For each test case, if required partition does not exist, print \(-1\). Otherwise, print an integer \(k\) — the number of segments in the partition.

Then in the \(i\)-th of the following \(k\) lines print two integers \(l_i\) and \(r_i\) — description of the \(i\)-th segment. The following conditions should be satisfied:

  • \(l_i \le r_i\) for each \(i\) from \(1\) to \(k\).
  • \(l_{i + 1} = r_i + 1\) for each \(i\) from \(1\) to \((k - 1)\).
  • \(l_1 = 1, r_k = n\).

If there are multiple correct partitions of the array, print any of them.

Example

input

1
2
3
4
5
6
7
8
9
4
4
1 1 1 1
6
-1 1 1 1 1 1
3
1 -1 1
1
1

output

1
2
3
4
5
6
7
1
1 4
2
1 3
4 6
-1
-1

Note

In the first test case we can build a partition of one segment of length \(4\). The sum of this segment will be equal to \(1 - 1 + 1 - 1 = 0\).

In the second test case we can build a partition of two segments of length \(3\). The sum of the first segment will be equal to \(-1 -1 + 1 = -1\), and the sum of the second segment: \(1 - 1 + 1 = 1\). So, the total sum will be equal to \(-1 + 1 = 0\).

In the third and in the fourth test cases it can be proved that there are no required partition.

思路与做法

直接看 C2 吧,C1 和 C2 的代码完全一致

代码参考

Show code

CodeForces_1753A1view raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
/*
* @Author: Tifa
* @Description: From <https://github.com/Tiphereth-A/CP-archives>
* !!! ATTENEION: All the context below is licensed under a
* GNU Affero General Public License, Version 3.
* See <https://www.gnu.org/licenses/agpl-3.0.txt>.
*/
#include <bits/stdc++.h>
template <class Tp>
using pi = std::pair<Tp, Tp>;
template <class Tp>
using vc = std::vector<Tp>;
struct CustomHash {
static uint64_t splitmix64(uint64_t x) {
x += 0x9e3779b97f4a7c15;
x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
return x ^ (x >> 31);
}
size_t operator()(uint64_t x) const {
static const uint64_t FIXED_RANDOM =
std::chrono::steady_clock::now().time_since_epoch().count();
return splitmix64(x + FIXED_RANDOM);
}
};
using pii = pi<int>;
#define for_(i, l, r, vars...) \
for (std::make_signed_t<decltype(l + r)> i = (l), i##end = (r), ##vars; \
i <= i##end; \
++i)
#define foreach_ref_(i, container) for (auto &i : (container))
#define all_(a) (a).begin(), (a).end()
#define run_exec_(expressions, post_process) \
{ \
expressions; \
post_process; \
}
#define run_return_void_(expressions) run_exec_(expressions, return)
#define read_var_(type, name) \
type name; \
std::cin >> name
#define read_container_(type, name, size) \
type name(size); \
foreach_ref_(i, name) std::cin >> i
template <class Tp>
constexpr auto chkmin(Tp &a, Tp b) -> bool {
return b < a ? a = b, true : false;
}
template <class Tp>
constexpr auto chkmax(Tp &a, Tp b) -> bool {
return a < b ? a = b, true : false;
}
template <class Tp>
constexpr auto ispow2(Tp i) -> bool {
return i && (i & -i) == i;
}
#define TPL_SIZE_(Tuple) std::tuple_size_v<std::remove_reference_t<Tuple>>
namespace tuple_detail_ {
template <std::size_t Begin, class Tuple, std::size_t... Is>
constexpr auto subtuple_impl_(Tuple &&t, std::index_sequence<Is...>) {
return std::make_tuple(std::get<Is + Begin>(t)...);
}
template <class Tuple, class BinOp, std::size_t... Is>
constexpr auto
apply2_impl_(BinOp &&f, Tuple &&lhs, Tuple &&rhs, std::index_sequence<Is...>) {
return std::make_tuple(
std::forward<BinOp>(f)(std::get<Is>(lhs), std::get<Is>(rhs))...);
}
} // namespace tuple_detail_
template <std::size_t Begin, std::size_t Len, class Tuple>
constexpr auto subtuple(Tuple &&t) {
static_assert(Begin <= TPL_SIZE_(Tuple) && Len <= TPL_SIZE_(Tuple) &&
Begin + Len <= TPL_SIZE_(Tuple),
"Out of range");
return tuple_detail_::subtuple_impl_<Begin>(t,
std::make_index_sequence<Len>());
}
template <std::size_t Pos, class Tp, class Tuple>
constexpr auto tuple_push(Tp &&v, Tuple &&t) {
static_assert(TPL_SIZE_(Tuple) > 0, "Pop from empty tuple");
return std::tuple_cat(subtuple<0, Pos>(t),
std::make_tuple(v),
subtuple<Pos, TPL_SIZE_(Tuple) - Pos>(t));
}
template <class Tp, class Tuple>
constexpr auto tuple_push_front(Tp &&v, Tuple &&t) {
return tuple_push<0>(v, t);
}
template <class Tp, class Tuple>
constexpr auto tuple_push_back(Tp &&v, Tuple &&t) {
return tuple_push<TPL_SIZE_(Tuple)>(v, t);
}
template <std::size_t Pos, class Tuple>
constexpr auto tuple_pop(Tuple &&t) {
static_assert(TPL_SIZE_(Tuple) > 0, "Pop from empty tuple");
return std::tuple_cat(subtuple<0, Pos>(t),
subtuple<Pos + 1, TPL_SIZE_(Tuple) - Pos - 1>(t));
}
template <class Tuple>
constexpr auto tuple_pop_front(Tuple &&t) {
return tuple_pop<0>(t);
}
template <class Tuple>
constexpr auto tuple_pop_back(Tuple &&t) {
return tuple_pop<TPL_SIZE_(Tuple) - 1>(t);
}
template <class Tuple, class BinOp>
constexpr auto apply2(BinOp &&f, Tuple &&lhs, Tuple &&rhs) {
return tuple_detail_::apply2_impl_(
f, lhs, rhs, std::make_index_sequence<TPL_SIZE_(Tuple)>());
}
#define OO_PTEQ_(op) \
template <class Tp, class Up> \
constexpr auto operator op(std::pair<Tp, Up> lhs, \
const std::pair<Tp, Up> &rhs) { \
return {lhs.first op rhs.first, lhs.second op rhs.second}; \
} \
template <class... Ts> \
constexpr auto operator op(std::tuple<Ts...> const &lhs, \
std::tuple<Ts...> const &rhs) { \
return apply2([](auto &&l, auto &&r) { return l op r; }, lhs, rhs); \
} \
template <class Tp, class Up> \
constexpr std::pair<Tp, Up> &operator op##=(std::pair<Tp, Up> &lhs, \
const std::pair<Tp, Up> &rhs) { \
lhs.first op## = rhs.first; \
lhs.second op## = rhs.second; \
return lhs; \
} \
template <class... Ts> \
constexpr auto operator op##=(std::tuple<Ts...> &lhs, \
const std::tuple<Ts...> &rhs) { \
return lhs = lhs op rhs; \
}
OO_PTEQ_(+)
OO_PTEQ_(-)
OO_PTEQ_(*)
OO_PTEQ_(/)
OO_PTEQ_(%)
OO_PTEQ_(&)
OO_PTEQ_(|)
OO_PTEQ_(^)
OO_PTEQ_(<<)
OO_PTEQ_(>>)
#undef OO_PTEQ_
#undef TPL_SIZE_
template <class Tp, class Up>
std::istream &operator>>(std::istream &is, std::pair<Tp, Up> &p) {
return is >> p.first >> p.second;
}
template <class Tp, class Up>
std::ostream &operator<<(std::ostream &os, const std::pair<Tp, Up> &p) {
return os << p.first << ' ' << p.second;
}
template <typename... Ts>
std::istream &operator>>(std::istream &is, std::tuple<Ts...> &p) {
std::apply([&](Ts &...targs) { ((is >> targs), ...); }, p);
return is;
}
template <typename... Ts>
std::ostream &operator<<(std::ostream &os, const std::tuple<Ts...> &p) {
std::apply(
[&](Ts const &...targs) {
std::size_t n{0};
((os << targs << (++n != sizeof...(Ts) ? " " : "")), ...);
},
p);
return os;
}
template <class Ch,
class Tr,
class Ct,
std::enable_if_t<std::is_same_v<decltype(std::declval<Ct>().begin()),
typename Ct::iterator> &&
std::is_same_v<decltype(std::declval<Ct>().end()),
typename Ct::iterator>> * = nullptr>
std::basic_ostream<Ch, Tr> &operator<<(std::basic_ostream<Ch, Tr> &os,
const Ct &x) {
if (x.begin() == x.end()) return os;
for (auto it = x.begin(); it != x.end() - 1; ++it) os << *it << ' ';
os << x.back();
return os;
}
using namespace std;
auto solve([[maybe_unused]] int t_ = 0) -> void {
read_var_(int, n);
read_container_(vc<int>, a, n);
int sum2 = accumulate(all_(a), 0);
if (sum2 & 1) run_return_void_(cout << "-1\n");
if (sum2 < 0) {
sum2 = -sum2;
transform(all_(a), a.begin(), negate<>());
}
int cnt = sum2 / 2;
vc<bool> ng(n);
for_(i, 1, n - 1) {
if (!cnt) break;
if (a[i] == 1) {
ng[i++] = 1;
--cnt;
}
}
if (cnt) run_return_void_(cout << "-1\n");
vc<pii> res;
int l = 1;
for_(i, 0, n - 2) {
if (ng[i] == ng[i + 1]) {
res.emplace_back(l, i + 1);
l = i + 2;
}
}
res.emplace_back(l, n);
cout << res.size() << '\n';
for (auto &&i : res) cout << i << '\n';
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int i_ = 0;
int t_ = 0;
std::cin >> t_;
for (i_ = 0; i_ < t_; ++i_) solve(i_);
return 0;
}

C2 - Make Nonzero Sum (hard version)

This is the hard version of the problem. The difference is that in this version the array contains zeros. You can make hacks only if both versions of the problem are solved.

You are given an array \([a_1, a_2, \ldots a_n]\) consisting of integers \(-1\), \(0\) and \(1\). You have to build a partition of this array into the set of segments \([l_1, r_1], [l_2, r_2], \ldots, [l_k, r_k]\) with the following property:

  • Denote the alternating sum of all elements of the \(i\)-th segment as \(s_i\): \(s_i\) = \(a_{l_i} - a_{l_i+1} + a_{l_i+2} - a_{l_i+3} + \ldots \pm a_{r_i}\). For example, the alternating sum of elements of segment \([2, 4]\) in array \([1, 0, -1, 1, 1]\) equals to \(0 - (-1) + 1 = 2\).
  • The sum of \(s_i\) over all segments of partition should be equal to zero.

Note that each \(s_i\) does not have to be equal to zero, this property is about sum of \(s_i\) over all segments of partition.

The set of segments \([l_1, r_1], [l_2, r_2], \ldots, [l_k, r_k]\) is called a partition of the array \(a\) of length \(n\) if \(1 = l_1 \le r_1, l_2 \le r_2, \ldots, l_k \le r_k = n\) and \(r_i + 1 = l_{i+1}\) for all \(i = 1, 2, \ldots k-1\). In other words, each element of the array must belong to exactly one segment.

You have to build a partition of the given array with properties described above or determine that such partition does not exist.

Note that it is not required to minimize the number of segments in the partition.

Input

Each test contains multiple test cases. The first line contains the number of test cases \(t\) (\(1 \le t \le 10\,000\)). Description of the test cases follows.

The first line of each test case contains an integer \(n\) (\(1 \le n \le 200\,000\)) — the length of array \(a\).

The second line of each test case contains \(n\) integers \(a_1, a_2, \ldots, a_n\) (\(a_i\) is \(-1\), \(0\), or \(1\)) — the elements of the given array.

It's guaranteed that the sum of \(n\) over all test cases does not exceed \(200\,000\).

Output

For each test case print an integer \(k\) — the number of segments in the partition. If required partition does not exist, print \(-1\).

If partition exists, in the \(i\)-th of the following \(k\) lines print two integers \(l_i\) and \(r_i\) — description of the \(i\)-th segment. The following conditions should be satisfied:

  • \(l_i \le r_i\) for each \(i\) from \(1\) to \(k\).
  • \(l_{i + 1} = r_i + 1\) for each \(i\) from \(1\) to \((k - 1)\).
  • \(l_1 = 1, r_k = n\).

If there are multiple correct partitions of the array, print any of them.

Example

input

1
2
3
4
5
6
7
8
9
10
11
5
4
0 0 0 0
7
-1 1 0 1 0 1 0
5
0 -1 1 0 1
3
1 0 1
1
1

output

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
4
1 1
2 2
3 3
4 4
4
1 1
2 2
3 5
6 7
-1
2
1 1
2 3
-1

Note

In the first test case we can build a partition of \(4\) segments — each of them will contain only one element of the array equals to \(0\). So the sum will be equal to \(0 + 0 + 0 + 0 = 0\).

In the second test case we can build a partition of \(4\) segments. The alternating sum of the first segment will be equal to \(-1\), the alternating sum of the second segment will be equal to \(1\), of the third segment — \(0 - 1 + 0 = -1\), of the fourth segment — \(1 - 0 = 1\). The sum will be equal to \(-1 + 1 -1 + 1 = 0\).

In the third test case it can be proved that the required partition does not exist.

思路与做法

题目相当于将 \(a_i\) 中某些项取相反数使得总和为 \(0\), 且不能修改连续的数

首先若 \(\sum a_i\) 为奇数则显然必定无解

\(\sum a_i<0\), 我们不妨先全局取反,不难发现这样不会影响结果

接下来我们从 \(a_2\) 开始找 \(1\) 然后取反,直到 \(\sum a_i=0\)

正确性显然

复杂度

\(O(n)\)

代码参考

Show code

CodeForces_1753A2view raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
/*
* @Author: Tifa
* @Description: From <https://github.com/Tiphereth-A/CP-archives>
* !!! ATTENEION: All the context below is licensed under a
* GNU Affero General Public License, Version 3.
* See <https://www.gnu.org/licenses/agpl-3.0.txt>.
*/
#include <bits/stdc++.h>
template <class Tp>
using pi = std::pair<Tp, Tp>;
template <class Tp>
using vc = std::vector<Tp>;
struct CustomHash {
static uint64_t splitmix64(uint64_t x) {
x += 0x9e3779b97f4a7c15;
x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
return x ^ (x >> 31);
}
size_t operator()(uint64_t x) const {
static const uint64_t FIXED_RANDOM =
std::chrono::steady_clock::now().time_since_epoch().count();
return splitmix64(x + FIXED_RANDOM);
}
};
using pii = pi<int>;
#define for_(i, l, r, vars...) \
for (std::make_signed_t<decltype(l + r)> i = (l), i##end = (r), ##vars; \
i <= i##end; \
++i)
#define foreach_ref_(i, container) for (auto &i : (container))
#define all_(a) (a).begin(), (a).end()
#define run_exec_(expressions, post_process) \
{ \
expressions; \
post_process; \
}
#define run_return_void_(expressions) run_exec_(expressions, return)
#define read_var_(type, name) \
type name; \
std::cin >> name
#define read_container_(type, name, size) \
type name(size); \
foreach_ref_(i, name) std::cin >> i
template <class Tp>
constexpr auto chkmin(Tp &a, Tp b) -> bool {
return b < a ? a = b, true : false;
}
template <class Tp>
constexpr auto chkmax(Tp &a, Tp b) -> bool {
return a < b ? a = b, true : false;
}
template <class Tp>
constexpr auto ispow2(Tp i) -> bool {
return i && (i & -i) == i;
}
#define TPL_SIZE_(Tuple) std::tuple_size_v<std::remove_reference_t<Tuple>>
namespace tuple_detail_ {
template <std::size_t Begin, class Tuple, std::size_t... Is>
constexpr auto subtuple_impl_(Tuple &&t, std::index_sequence<Is...>) {
return std::make_tuple(std::get<Is + Begin>(t)...);
}
template <class Tuple, class BinOp, std::size_t... Is>
constexpr auto
apply2_impl_(BinOp &&f, Tuple &&lhs, Tuple &&rhs, std::index_sequence<Is...>) {
return std::make_tuple(
std::forward<BinOp>(f)(std::get<Is>(lhs), std::get<Is>(rhs))...);
}
} // namespace tuple_detail_
template <std::size_t Begin, std::size_t Len, class Tuple>
constexpr auto subtuple(Tuple &&t) {
static_assert(Begin <= TPL_SIZE_(Tuple) && Len <= TPL_SIZE_(Tuple) &&
Begin + Len <= TPL_SIZE_(Tuple),
"Out of range");
return tuple_detail_::subtuple_impl_<Begin>(t,
std::make_index_sequence<Len>());
}
template <std::size_t Pos, class Tp, class Tuple>
constexpr auto tuple_push(Tp &&v, Tuple &&t) {
static_assert(TPL_SIZE_(Tuple) > 0, "Pop from empty tuple");
return std::tuple_cat(subtuple<0, Pos>(t),
std::make_tuple(v),
subtuple<Pos, TPL_SIZE_(Tuple) - Pos>(t));
}
template <class Tp, class Tuple>
constexpr auto tuple_push_front(Tp &&v, Tuple &&t) {
return tuple_push<0>(v, t);
}
template <class Tp, class Tuple>
constexpr auto tuple_push_back(Tp &&v, Tuple &&t) {
return tuple_push<TPL_SIZE_(Tuple)>(v, t);
}
template <std::size_t Pos, class Tuple>
constexpr auto tuple_pop(Tuple &&t) {
static_assert(TPL_SIZE_(Tuple) > 0, "Pop from empty tuple");
return std::tuple_cat(subtuple<0, Pos>(t),
subtuple<Pos + 1, TPL_SIZE_(Tuple) - Pos - 1>(t));
}
template <class Tuple>
constexpr auto tuple_pop_front(Tuple &&t) {
return tuple_pop<0>(t);
}
template <class Tuple>
constexpr auto tuple_pop_back(Tuple &&t) {
return tuple_pop<TPL_SIZE_(Tuple) - 1>(t);
}
template <class Tuple, class BinOp>
constexpr auto apply2(BinOp &&f, Tuple &&lhs, Tuple &&rhs) {
return tuple_detail_::apply2_impl_(
f, lhs, rhs, std::make_index_sequence<TPL_SIZE_(Tuple)>());
}
#define OO_PTEQ_(op) \
template <class Tp, class Up> \
constexpr auto operator op(std::pair<Tp, Up> lhs, \
const std::pair<Tp, Up> &rhs) { \
return {lhs.first op rhs.first, lhs.second op rhs.second}; \
} \
template <class... Ts> \
constexpr auto operator op(std::tuple<Ts...> const &lhs, \
std::tuple<Ts...> const &rhs) { \
return apply2([](auto &&l, auto &&r) { return l op r; }, lhs, rhs); \
} \
template <class Tp, class Up> \
constexpr std::pair<Tp, Up> &operator op##=(std::pair<Tp, Up> &lhs, \
const std::pair<Tp, Up> &rhs) { \
lhs.first op## = rhs.first; \
lhs.second op## = rhs.second; \
return lhs; \
} \
template <class... Ts> \
constexpr auto operator op##=(std::tuple<Ts...> &lhs, \
const std::tuple<Ts...> &rhs) { \
return lhs = lhs op rhs; \
}
OO_PTEQ_(+)
OO_PTEQ_(-)
OO_PTEQ_(*)
OO_PTEQ_(/)
OO_PTEQ_(%)
OO_PTEQ_(&)
OO_PTEQ_(|)
OO_PTEQ_(^)
OO_PTEQ_(<<)
OO_PTEQ_(>>)
#undef OO_PTEQ_
#undef TPL_SIZE_
template <class Tp, class Up>
std::istream &operator>>(std::istream &is, std::pair<Tp, Up> &p) {
return is >> p.first >> p.second;
}
template <class Tp, class Up>
std::ostream &operator<<(std::ostream &os, const std::pair<Tp, Up> &p) {
return os << p.first << ' ' << p.second;
}
template <typename... Ts>
std::istream &operator>>(std::istream &is, std::tuple<Ts...> &p) {
std::apply([&](Ts &...targs) { ((is >> targs), ...); }, p);
return is;
}
template <typename... Ts>
std::ostream &operator<<(std::ostream &os, const std::tuple<Ts...> &p) {
std::apply(
[&](Ts const &...targs) {
std::size_t n{0};
((os << targs << (++n != sizeof...(Ts) ? " " : "")), ...);
},
p);
return os;
}
template <class Ch,
class Tr,
class Ct,
std::enable_if_t<std::is_same_v<decltype(std::declval<Ct>().begin()),
typename Ct::iterator> &&
std::is_same_v<decltype(std::declval<Ct>().end()),
typename Ct::iterator>> * = nullptr>
std::basic_ostream<Ch, Tr> &operator<<(std::basic_ostream<Ch, Tr> &os,
const Ct &x) {
if (x.begin() == x.end()) return os;
for (auto it = x.begin(); it != x.end() - 1; ++it) os << *it << ' ';
os << x.back();
return os;
}
using namespace std;
auto solve([[maybe_unused]] int t_ = 0) -> void {
read_var_(int, n);
read_container_(vc<int>, a, n);
int sum2 = accumulate(all_(a), 0);
if (sum2 & 1) run_return_void_(cout << "-1\n");
if (sum2 < 0) {
sum2 = -sum2;
transform(all_(a), a.begin(), negate<>());
}
int cnt = sum2 / 2;
vc<bool> ng(n);
for_(i, 1, n - 1) {
if (!cnt) break;
if (a[i] == 1) {
ng[i++] = 1;
--cnt;
}
}
if (cnt) run_return_void_(cout << "-1\n");
vc<pii> res;
int l = 1;
for_(i, 0, n - 2) {
if (ng[i] == ng[i + 1]) {
res.emplace_back(l, i + 1);
l = i + 2;
}
}
res.emplace_back(l, n);
cout << res.size() << '\n';
for (auto &&i : res) cout << i << '\n';
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int i_ = 0;
int t_ = 0;
std::cin >> t_;
for (i_ = 0; i_ < t_; ++i_) solve(i_);
return 0;
}

D - Factorial Divisibility

You are given an integer \(x\) and an array of integers \(a_1, a_2, \ldots, a_n\). You have to determine if the number \(a_1! + a_2! + \ldots + a_n!\) is divisible by \(x!\).

Here \(k!\) is a factorial of \(k\) — the product of all positive integers less than or equal to \(k\). For example, \(3! = 1 \cdot 2 \cdot 3 = 6\), and \(5! = 1 \cdot 2 \cdot 3 \cdot 4 \cdot 5 = 120\).

Input

The first line contains two integers \(n\) and \(x\) (\(1 \le n \le 500\,000\), \(1 \le x \le 500\,000\)).

The second line contains \(n\) integers \(a_1, a_2, \ldots, a_n\) (\(1 \le a_i \le x\)) — elements of given array.

Output

In the only line print "Yes" (without quotes) if \(a_1! + a_2! + \ldots + a_n!\) is divisible by \(x!\), and "No" (without quotes) otherwise.

Examples

input

1
2
6 4
3 2 2 2 3 3

output

1
Yes

input

1
2
8 3
3 2 2 2 2 2 1 1

output

1
Yes

input

1
2
7 8
7 7 7 7 7 7 7

output

1
No

input

1
2
10 5
4 3 2 1 4 3 2 4 3 4

output

1
No

input

1
2
2 500000
499999 499999

output

1
No

Note

In the first example \(3! + 2! + 2! + 2! + 3! + 3! = 6 + 2 + 2 + 2 + 6 + 6 = 24\). Number \(24\) is divisible by \(4! = 24\).

In the second example \(3! + 2! + 2! + 2! + 2! + 2! + 1! + 1! = 18\), is divisible by \(3! = 6\).

In the third example \(7! + 7! + 7! + 7! + 7! + 7! + 7! = 7 \cdot 7!\). It is easy to prove that this number is not divisible by \(8!\).

思路与做法

注意到

\[ \sum_{i=0}^{k-1}a_i i!<k!,~a_i\leq i \]

所以 \(a_i\) 将视作 "阶乘进制数", 然后按 \((i+1)*i!=(i+1)!\) 进位,最后看 \(\bmod k!\) 后有无余项即可

复杂度

\(O(k)\)

代码参考

Show code

CodeForces_1753Bview raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
/*
* @Author: Tifa
* @Description: From <https://github.com/Tiphereth-A/CP-archives>
* !!! ATTENEION: All the context below is licensed under a
* GNU Affero General Public License, Version 3.
* See <https://www.gnu.org/licenses/agpl-3.0.txt>.
*/
#include <bits/stdc++.h>
template <class Tp>
using vc = std::vector<Tp>;
struct CustomHash {
static uint64_t splitmix64(uint64_t x) {
x += 0x9e3779b97f4a7c15;
x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
return x ^ (x >> 31);
}
size_t operator()(uint64_t x) const {
static const uint64_t FIXED_RANDOM =
std::chrono::steady_clock::now().time_since_epoch().count();
return splitmix64(x + FIXED_RANDOM);
}
};
#define for_(i, l, r, vars...) \
for (std::make_signed_t<decltype(l + r)> i = (l), i##end = (r), ##vars; \
i <= i##end; \
++i)
#define read_var_(type, name) \
type name; \
std::cin >> name
template <class Tp>
constexpr auto chkmin(Tp &a, Tp b) -> bool {
return b < a ? a = b, true : false;
}
template <class Tp>
constexpr auto chkmax(Tp &a, Tp b) -> bool {
return a < b ? a = b, true : false;
}
template <class Tp>
constexpr auto ispow2(Tp i) -> bool {
return i && (i & -i) == i;
}
#define TPL_SIZE_(Tuple) std::tuple_size_v<std::remove_reference_t<Tuple>>
namespace tuple_detail_ {
template <std::size_t Begin, class Tuple, std::size_t... Is>
constexpr auto subtuple_impl_(Tuple &&t, std::index_sequence<Is...>) {
return std::make_tuple(std::get<Is + Begin>(t)...);
}
template <class Tuple, class BinOp, std::size_t... Is>
constexpr auto
apply2_impl_(BinOp &&f, Tuple &&lhs, Tuple &&rhs, std::index_sequence<Is...>) {
return std::make_tuple(
std::forward<BinOp>(f)(std::get<Is>(lhs), std::get<Is>(rhs))...);
}
} // namespace tuple_detail_
template <std::size_t Begin, std::size_t Len, class Tuple>
constexpr auto subtuple(Tuple &&t) {
static_assert(Begin <= TPL_SIZE_(Tuple) && Len <= TPL_SIZE_(Tuple) &&
Begin + Len <= TPL_SIZE_(Tuple),
"Out of range");
return tuple_detail_::subtuple_impl_<Begin>(t,
std::make_index_sequence<Len>());
}
template <std::size_t Pos, class Tp, class Tuple>
constexpr auto tuple_push(Tp &&v, Tuple &&t) {
static_assert(TPL_SIZE_(Tuple) > 0, "Pop from empty tuple");
return std::tuple_cat(subtuple<0, Pos>(t),
std::make_tuple(v),
subtuple<Pos, TPL_SIZE_(Tuple) - Pos>(t));
}
template <class Tp, class Tuple>
constexpr auto tuple_push_front(Tp &&v, Tuple &&t) {
return tuple_push<0>(v, t);
}
template <class Tp, class Tuple>
constexpr auto tuple_push_back(Tp &&v, Tuple &&t) {
return tuple_push<TPL_SIZE_(Tuple)>(v, t);
}
template <std::size_t Pos, class Tuple>
constexpr auto tuple_pop(Tuple &&t) {
static_assert(TPL_SIZE_(Tuple) > 0, "Pop from empty tuple");
return std::tuple_cat(subtuple<0, Pos>(t),
subtuple<Pos + 1, TPL_SIZE_(Tuple) - Pos - 1>(t));
}
template <class Tuple>
constexpr auto tuple_pop_front(Tuple &&t) {
return tuple_pop<0>(t);
}
template <class Tuple>
constexpr auto tuple_pop_back(Tuple &&t) {
return tuple_pop<TPL_SIZE_(Tuple) - 1>(t);
}
template <class Tuple, class BinOp>
constexpr auto apply2(BinOp &&f, Tuple &&lhs, Tuple &&rhs) {
return tuple_detail_::apply2_impl_(
f, lhs, rhs, std::make_index_sequence<TPL_SIZE_(Tuple)>());
}
#define OO_PTEQ_(op) \
template <class Tp, class Up> \
constexpr auto operator op(std::pair<Tp, Up> lhs, \
const std::pair<Tp, Up> &rhs) { \
return {lhs.first op rhs.first, lhs.second op rhs.second}; \
} \
template <class... Ts> \
constexpr auto operator op(std::tuple<Ts...> const &lhs, \
std::tuple<Ts...> const &rhs) { \
return apply2([](auto &&l, auto &&r) { return l op r; }, lhs, rhs); \
} \
template <class Tp, class Up> \
constexpr std::pair<Tp, Up> &operator op##=(std::pair<Tp, Up> &lhs, \
const std::pair<Tp, Up> &rhs) { \
lhs.first op## = rhs.first; \
lhs.second op## = rhs.second; \
return lhs; \
} \
template <class... Ts> \
constexpr auto operator op##=(std::tuple<Ts...> &lhs, \
const std::tuple<Ts...> &rhs) { \
return lhs = lhs op rhs; \
}
OO_PTEQ_(+)
OO_PTEQ_(-)
OO_PTEQ_(*)
OO_PTEQ_(/)
OO_PTEQ_(%)
OO_PTEQ_(&)
OO_PTEQ_(|)
OO_PTEQ_(^)
OO_PTEQ_(<<)
OO_PTEQ_(>>)
#undef OO_PTEQ_
#undef TPL_SIZE_
template <class Tp, class Up>
std::istream &operator>>(std::istream &is, std::pair<Tp, Up> &p) {
return is >> p.first >> p.second;
}
template <class Tp, class Up>
std::ostream &operator<<(std::ostream &os, const std::pair<Tp, Up> &p) {
return os << p.first << ' ' << p.second;
}
template <typename... Ts>
std::istream &operator>>(std::istream &is, std::tuple<Ts...> &p) {
std::apply([&](Ts &...targs) { ((is >> targs), ...); }, p);
return is;
}
template <typename... Ts>
std::ostream &operator<<(std::ostream &os, const std::tuple<Ts...> &p) {
std::apply(
[&](Ts const &...targs) {
std::size_t n{0};
((os << targs << (++n != sizeof...(Ts) ? " " : "")), ...);
},
p);
return os;
}
template <class Ch,
class Tr,
class Ct,
std::enable_if_t<std::is_same_v<decltype(std::declval<Ct>().begin()),
typename Ct::iterator> &&
std::is_same_v<decltype(std::declval<Ct>().end()),
typename Ct::iterator>> * = nullptr>
std::basic_ostream<Ch, Tr> &operator<<(std::basic_ostream<Ch, Tr> &os,
const Ct &x) {
if (x.begin() == x.end()) return os;
for (auto it = x.begin(); it != x.end() - 1; ++it) os << *it << ' ';
os << x.back();
return os;
}
const std::string RES_Yn[2] = {"No", "Yes"};
using namespace std;
auto solve([[maybe_unused]] int t_ = 0) -> void {
read_var_(int, n);
read_var_(int, x);
vc<int> cnt(x + 1);
for_(i, 1, n, a) {
cin >> a;
++cnt[a];
}
for_(i, 0, x - 1) {
cnt[i + 1] += cnt[i] / (i + 1);
cnt[i] %= i + 1;
}
cout << RES_Yn[all_of(cnt.begin(), cnt.begin() + x, [](auto &&_) {
return _ == 0;
})] << '\n';
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int i_ = 0;
solve(i_);
return 0;
}

E - Wish I Knew How to Sort

You are given a binary array \(a\) (all elements of the array are \(0\) or \(1\)) of length \(n\). You wish to sort this array, but unfortunately, your algorithms teacher forgot to teach you sorting algorithms. You perform the following operations until \(a\) is sorted:

  1. Choose two random indices \(i\) and \(j\) such that \(i < j\). Indices are chosen equally probable among all pairs of indices \((i, j)\) such that \(1 \le i < j \le n\).
  2. If \(a_i > a_j\), then swap elements \(a_i\) and \(a_j\).

What is the expected number of such operations you will perform before the array becomes sorted?

It can be shown that the answer can be expressed as an irreducible fraction \(\frac{p}{q}\), where \(p\) and \(q\) are integers and \(q \not \equiv 0 \pmod{998\,244\,353}\). ### Output the integer equal to \(p \cdot q^{-1} \bmod 998\,244\,353\). In other words, output such an integer \(x\) that \(0 \le x < 998\,244\,353\) and \(x \cdot q \equiv p \pmod{998\,244\,353}\).

Input

Each test contains multiple test cases. The first line contains the number of test cases \(t\) (\(1 \le t \le 10^5\)). Description of the test cases follows.

The first line of each test case contains an integer \(n\) (\(1 \le n \le 200\,000\)) — the number of elements in the binary array.

The second line of each test case contains \(n\) integers \(a_1, a_2, \ldots, a_n\) (\(a_i \in \{0, 1\}\)) — elements of the array.

It's guaranteed that sum of \(n\) over all test cases does not exceed \(200\,000\).

Output

For each test case print one integer — the value \(p \cdot q^{-1} \bmod 998\,244\,353\).

Example

input

1
2
3
4
5
6
7
3
3
0 1 0
5
0 0 1 1 1
6
1 1 1 0 0 1

output

1
2
3
3
0
249561107

Note

Consider the first test case. If the pair of indices \((2, 3)\) will be chosen, these elements will be swapped and array will become sorted. Otherwise, if one of pairs \((1, 2)\) or \((1, 3)\) will be selected, nothing will happen. So, the probability that the array will become sorted after one operation is \(\frac{1}{3}\), the probability that the array will become sorted after two operations is \(\frac{2}{3} \cdot \frac{1}{3}\), the probability that the array will become sorted after three operations is \(\frac{2}{3} \cdot \frac{2}{3} \cdot \frac{1}{3}\) and so on. The expected number of operations is \(\sum \limits_{i=1}^{\infty} \left(\frac{2}{3} \right)^{i - 1} \cdot \frac{1}{3} \cdot i = 3\).

In the second test case the array is already sorted so the expected number of operations is zero.

In the third test case the expected number of operations equals to \(\frac{75}{4}\) so the answer is \(75 \cdot 4^{-1} \equiv 249\,561\,107 \pmod {998\,244\,353}\).

思路与做法

  • \[ s=\sum[a_i=0] \]
  • \[ t=\sum_{i=1}^s[a_i=0] \]
  • \(f(i)\) 为当前 \(i\) 位是 \(0\) 时调整步数的期望

  • \(f(s)=0\)
  • \(f(x)=1+f(x)(1-p)+f(x+1)p\), 其中 \(p=\frac{2(s-x)^2}{n(n-1)}\)

答案即为 \(f(t)\)

复杂度

\(O(n)\)

代码参考

Show code

CodeForces_1753Cview raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
/*
* @Author: Tifa
* @Description: From <https://github.com/Tiphereth-A/CP-archives>
* !!! ATTENEION: All the context below is licensed under a
* GNU Affero General Public License, Version 3.
* See <https://www.gnu.org/licenses/agpl-3.0.txt>.
*/
#include <bits/stdc++.h>
template <class Tp>
using vc = std::vector<Tp>;
struct CustomHash {
static uint64_t splitmix64(uint64_t x) {
x += 0x9e3779b97f4a7c15;
x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
return x ^ (x >> 31);
}
size_t operator()(uint64_t x) const {
static const uint64_t FIXED_RANDOM =
std::chrono::steady_clock::now().time_since_epoch().count();
return splitmix64(x + FIXED_RANDOM);
}
};
using i64 = int64_t;
#define rfor_(i, r, l, vars...) \
for (std::make_signed_t<decltype(r - l)> i = (r), i##end = (l), ##vars; \
i >= i##end; \
--i)
#define foreach_ref_(i, container) for (auto &i : (container))
#define all_(a) (a).begin(), (a).end()
#define read_var_(type, name) \
type name; \
std::cin >> name
#define read_container_(type, name, size) \
type name(size); \
foreach_ref_(i, name) std::cin >> i
template <class Tp>
constexpr auto chkmin(Tp &a, Tp b) -> bool {
return b < a ? a = b, true : false;
}
template <class Tp>
constexpr auto chkmax(Tp &a, Tp b) -> bool {
return a < b ? a = b, true : false;
}
template <class Tp>
constexpr auto ispow2(Tp i) -> bool {
return i && (i & -i) == i;
}
#define TPL_SIZE_(Tuple) std::tuple_size_v<std::remove_reference_t<Tuple>>
namespace tuple_detail_ {
template <std::size_t Begin, class Tuple, std::size_t... Is>
constexpr auto subtuple_impl_(Tuple &&t, std::index_sequence<Is...>) {
return std::make_tuple(std::get<Is + Begin>(t)...);
}
template <class Tuple, class BinOp, std::size_t... Is>
constexpr auto
apply2_impl_(BinOp &&f, Tuple &&lhs, Tuple &&rhs, std::index_sequence<Is...>) {
return std::make_tuple(
std::forward<BinOp>(f)(std::get<Is>(lhs), std::get<Is>(rhs))...);
}
} // namespace tuple_detail_
template <std::size_t Begin, std::size_t Len, class Tuple>
constexpr auto subtuple(Tuple &&t) {
static_assert(Begin <= TPL_SIZE_(Tuple) && Len <= TPL_SIZE_(Tuple) &&
Begin + Len <= TPL_SIZE_(Tuple),
"Out of range");
return tuple_detail_::subtuple_impl_<Begin>(t,
std::make_index_sequence<Len>());
}
template <std::size_t Pos, class Tp, class Tuple>
constexpr auto tuple_push(Tp &&v, Tuple &&t) {
static_assert(TPL_SIZE_(Tuple) > 0, "Pop from empty tuple");
return std::tuple_cat(subtuple<0, Pos>(t),
std::make_tuple(v),
subtuple<Pos, TPL_SIZE_(Tuple) - Pos>(t));
}
template <class Tp, class Tuple>
constexpr auto tuple_push_front(Tp &&v, Tuple &&t) {
return tuple_push<0>(v, t);
}
template <class Tp, class Tuple>
constexpr auto tuple_push_back(Tp &&v, Tuple &&t) {
return tuple_push<TPL_SIZE_(Tuple)>(v, t);
}
template <std::size_t Pos, class Tuple>
constexpr auto tuple_pop(Tuple &&t) {
static_assert(TPL_SIZE_(Tuple) > 0, "Pop from empty tuple");
return std::tuple_cat(subtuple<0, Pos>(t),
subtuple<Pos + 1, TPL_SIZE_(Tuple) - Pos - 1>(t));
}
template <class Tuple>
constexpr auto tuple_pop_front(Tuple &&t) {
return tuple_pop<0>(t);
}
template <class Tuple>
constexpr auto tuple_pop_back(Tuple &&t) {
return tuple_pop<TPL_SIZE_(Tuple) - 1>(t);
}
template <class Tuple, class BinOp>
constexpr auto apply2(BinOp &&f, Tuple &&lhs, Tuple &&rhs) {
return tuple_detail_::apply2_impl_(
f, lhs, rhs, std::make_index_sequence<TPL_SIZE_(Tuple)>());
}
#define OO_PTEQ_(op) \
template <class Tp, class Up> \
constexpr auto operator op(std::pair<Tp, Up> lhs, \
const std::pair<Tp, Up> &rhs) { \
return {lhs.first op rhs.first, lhs.second op rhs.second}; \
} \
template <class... Ts> \
constexpr auto operator op(std::tuple<Ts...> const &lhs, \
std::tuple<Ts...> const &rhs) { \
return apply2([](auto &&l, auto &&r) { return l op r; }, lhs, rhs); \
} \
template <class Tp, class Up> \
constexpr std::pair<Tp, Up> &operator op##=(std::pair<Tp, Up> &lhs, \
const std::pair<Tp, Up> &rhs) { \
lhs.first op## = rhs.first; \
lhs.second op## = rhs.second; \
return lhs; \
} \
template <class... Ts> \
constexpr auto operator op##=(std::tuple<Ts...> &lhs, \
const std::tuple<Ts...> &rhs) { \
return lhs = lhs op rhs; \
}
OO_PTEQ_(+)
OO_PTEQ_(-)
OO_PTEQ_(*)
OO_PTEQ_(/)
OO_PTEQ_(%)
OO_PTEQ_(&)
OO_PTEQ_(|)
OO_PTEQ_(^)
OO_PTEQ_(<<)
OO_PTEQ_(>>)
#undef OO_PTEQ_
#undef TPL_SIZE_
template <class Tp, class Up>
std::istream &operator>>(std::istream &is, std::pair<Tp, Up> &p) {
return is >> p.first >> p.second;
}
template <class Tp, class Up>
std::ostream &operator<<(std::ostream &os, const std::pair<Tp, Up> &p) {
return os << p.first << ' ' << p.second;
}
template <typename... Ts>
std::istream &operator>>(std::istream &is, std::tuple<Ts...> &p) {
std::apply([&](Ts &...targs) { ((is >> targs), ...); }, p);
return is;
}
template <typename... Ts>
std::ostream &operator<<(std::ostream &os, const std::tuple<Ts...> &p) {
std::apply(
[&](Ts const &...targs) {
std::size_t n{0};
((os << targs << (++n != sizeof...(Ts) ? " " : "")), ...);
},
p);
return os;
}
template <class Ch,
class Tr,
class Ct,
std::enable_if_t<std::is_same_v<decltype(std::declval<Ct>().begin()),
typename Ct::iterator> &&
std::is_same_v<decltype(std::declval<Ct>().end()),
typename Ct::iterator>> * = nullptr>
std::basic_ostream<Ch, Tr> &operator<<(std::basic_ostream<Ch, Tr> &os,
const Ct &x) {
if (x.begin() == x.end()) return os;
for (auto it = x.begin(); it != x.end() - 1; ++it) os << *it << ' ';
os << x.back();
return os;
}
const i64 MOD = 998244353;
using namespace std;
constexpr int64_t inverse(int64_t n, int64_t mod) {
int64_t b = mod, m0 = 0;
for (int64_t q = 0, _ = 0, m1 = 1; n;) {
_ = b - n * (q = b / n);
b = n;
n = _;
_ = m0 - m1 * q;
m0 = m1;
m1 = _;
}
return (m0 + (m0 < 0 ? mod / b : 0)) % mod;
}
auto solve([[maybe_unused]] int t_ = 0) -> void {
read_var_(i64, n);
read_container_(vc<int>, a, n);
i64 cnt0 = count_if(all_(a), [](auto &&x) { return x == 0; }),
cnte =
count_if(a.begin(), a.begin() + cnt0, [](auto &&x) { return x == 0; });
vc<i64> f(cnt0 + 1);
i64 _ = n * (n - 1) % MOD;
rfor_(i, cnt0 - 1, cnte) {
i64 p = 2 * (cnt0 - i) * (cnt0 - i) % MOD;
f[i] = (f[i + 1] + _ * inverse(p, MOD) % MOD) % MOD;
}
cout << f[cnte] << '\n';
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int i_ = 0;
int t_ = 0;
std::cin >> t_;
for (i_ = 0; i_ < t_; ++i_) solve(i_);
return 0;
}

F - The Beach

Andrew loves the sea. That's why, at the height of the summer season, he decided to go to the beach, taking a sunbed with him to sunbathe.

The beach is a rectangular field with \(n\) rows and \(m\) columns. Some cells of the beach are free, some have roads, stones, shops and other non-movable objects. Some of two adjacent along the side cells can have sunbeds located either horizontally or vertically.

Andrew hopes to put his sunbed somewhere, but that's a bad luck, there may no longer be free places for him! That's why Andrew asked you to help him to find a free place for his sunbed. Andrew's sunbed also should be places on two adjacent cells.

If there are no two adjacent free cells, then in order to free some place for a sunbed, you will have to disturb other tourists. You can do the following actions:

  • Come to some sunbed and, after causing \(p\) units of discomfort to its owner, lift the sunbed by one of its sides and rotate it by \(90\) degrees. One half of the sunbed must remain in the same cell and another half of the sunbed must move to the free cell. At the same time, anything could be on the way of a sunbed during the rotation.

    Rotation of the sunbed by 90 degrees around cell (1, 2).

  • Come to some sunbed and, after causing \(q\) units of discomfort to its owner, shift the sunbed along its long side by one cell. One half of the sunbed must move to the place of another, and another — to the free cell.

Shift of the sunbed by one cell to the right.

In any moment each sunbed occupies two adjacent free cells. You cannot move more than one sunbed at a time.

Help Andrew to free a space for his sunbed, causing the minimum possible number of units of discomfort to other tourists, or detect that it is impossible.

Input

The first line contains two integers \(n\) and \(m\) (\(1 \le n, m \le 300\,000\), \(1 \le n \cdot m \le 300\,000\)) — the number of rows and columns in rectangle.

The second line contains two integers \(p\) and \(q\) (\(1 \le p, q \le 10^9\)) — the number of units of discomfort caused by rotation and shift of a sunbed, respectively.

Each of the following \(n\) lines contains \(m\) characters, describing cells of the rectangle. Each lines consists of characters "L", "R", "D", "U", "." and "#", denoting the type of the cell. Characters "L", "R", "D" and "U" denote a half of a sunbed placed in the cell — left, right, bottom and top half, respectively. Character "." denotes a free cell and character "#" — a cell, occupied by some non-movable object.

Output

Print one integer — the minimum possible number of units of discomfort, caused to other tourists, to free a space for a sunbed. If it is impossible to free a space for a sunbed, print \(-1\).

Examples

input

1
2
3
4
2 5
5 2
.LR##
##LR.

output

1
4

input

1
2
3
4
2 3
4 5
LR.
#.#

output

1
-1

input

1
2
3
4
5
6
4 3
10 10
.LR
###
UU#
DD.

output

1
-1

input

1
2
3
4
5
3 6
10 7
.U##.#
#DLR##
.##LR.

output

1
24

Note

In the first example we can shift upper sunbed to the left and lower sunbed — to the right. Andrew will be able to put his sunbed vertically in the middle of the beach. We well cause \(2 + 2 = 4\) units of discomfort. It is easy to prove that it is an optimal answer.

Optimal strategy in the first example (Andrew's sunbed is colored white).

In the second example it is impossible to free a space for Andrew's sunbed. All possible states of the beach after any rotates and shifts are illustrated in the problem statement.

思路与做法

显然若有解,每个沙滩椅最多只需移动一次

为方便理解,将沙滩按国际象棋棋盘的方式染色。我们考虑将移动沙滩椅转为移动空位,显然每个空位都只能移动到同色且 Manhattan 距离为 \(2\) 的位置上

那我们可以将每个位置视作点,空位的移动方式视作边跑一下最短路即可

复杂度

\(O(nm\log (nm))\)

代码参考

Show code

CodeForces_1753Dview raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
/*
* @Author: Tifa
* @Description: From <https://github.com/Tiphereth-A/CP-archives>
* !!! ATTENEION: All the context below is licensed under a
* GNU Affero General Public License, Version 3.
* See <https://www.gnu.org/licenses/agpl-3.0.txt>.
*/
#include <bits/stdc++.h>
template <class Tp>
using pi = std::pair<Tp, Tp>;
template <class Tp>
using vc = std::vector<Tp>;
template <class Tp>
using pqg = std::priority_queue<Tp, std::vector<Tp>, std::greater<Tp>>;
struct CustomHash {
static uint64_t splitmix64(uint64_t x) {
x += 0x9e3779b97f4a7c15;
x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
return x ^ (x >> 31);
}
size_t operator()(uint64_t x) const {
static const uint64_t FIXED_RANDOM =
std::chrono::steady_clock::now().time_since_epoch().count();
return splitmix64(x + FIXED_RANDOM);
}
};
using u32 = uint32_t;
using i64 = int64_t;
using pii = pi<int>;
#define for_(i, l, r, vars...) \
for (std::make_signed_t<decltype(l + r)> i = (l), i##end = (r), ##vars; \
i <= i##end; \
++i)
#define foreach_ref_(i, container) for (auto &i : (container))
#define read_container_(type, name, size) \
type name(size); \
foreach_ref_(i, name) std::cin >> i
template <class Tp>
constexpr auto chkmin(Tp &a, Tp b) -> bool {
return b < a ? a = b, true : false;
}
template <class Tp>
constexpr auto chkmax(Tp &a, Tp b) -> bool {
return a < b ? a = b, true : false;
}
template <class Tp>
constexpr auto ispow2(Tp i) -> bool {
return i && (i & -i) == i;
}
#define TPL_SIZE_(Tuple) std::tuple_size_v<std::remove_reference_t<Tuple>>
namespace tuple_detail_ {
template <std::size_t Begin, class Tuple, std::size_t... Is>
constexpr auto subtuple_impl_(Tuple &&t, std::index_sequence<Is...>) {
return std::make_tuple(std::get<Is + Begin>(t)...);
}
template <class Tuple, class BinOp, std::size_t... Is>
constexpr auto
apply2_impl_(BinOp &&f, Tuple &&lhs, Tuple &&rhs, std::index_sequence<Is...>) {
return std::make_tuple(
std::forward<BinOp>(f)(std::get<Is>(lhs), std::get<Is>(rhs))...);
}
} // namespace tuple_detail_
template <std::size_t Begin, std::size_t Len, class Tuple>
constexpr auto subtuple(Tuple &&t) {
static_assert(Begin <= TPL_SIZE_(Tuple) && Len <= TPL_SIZE_(Tuple) &&
Begin + Len <= TPL_SIZE_(Tuple),
"Out of range");
return tuple_detail_::subtuple_impl_<Begin>(t,
std::make_index_sequence<Len>());
}
template <std::size_t Pos, class Tp, class Tuple>
constexpr auto tuple_push(Tp &&v, Tuple &&t) {
static_assert(TPL_SIZE_(Tuple) > 0, "Pop from empty tuple");
return std::tuple_cat(subtuple<0, Pos>(t),
std::make_tuple(v),
subtuple<Pos, TPL_SIZE_(Tuple) - Pos>(t));
}
template <class Tp, class Tuple>
constexpr auto tuple_push_front(Tp &&v, Tuple &&t) {
return tuple_push<0>(v, t);
}
template <class Tp, class Tuple>
constexpr auto tuple_push_back(Tp &&v, Tuple &&t) {
return tuple_push<TPL_SIZE_(Tuple)>(v, t);
}
template <std::size_t Pos, class Tuple>
constexpr auto tuple_pop(Tuple &&t) {
static_assert(TPL_SIZE_(Tuple) > 0, "Pop from empty tuple");
return std::tuple_cat(subtuple<0, Pos>(t),
subtuple<Pos + 1, TPL_SIZE_(Tuple) - Pos - 1>(t));
}
template <class Tuple>
constexpr auto tuple_pop_front(Tuple &&t) {
return tuple_pop<0>(t);
}
template <class Tuple>
constexpr auto tuple_pop_back(Tuple &&t) {
return tuple_pop<TPL_SIZE_(Tuple) - 1>(t);
}
template <class Tuple, class BinOp>
constexpr auto apply2(BinOp &&f, Tuple &&lhs, Tuple &&rhs) {
return tuple_detail_::apply2_impl_(
f, lhs, rhs, std::make_index_sequence<TPL_SIZE_(Tuple)>());
}
#define OO_PTEQ_(op) \
template <class Tp, class Up> \
constexpr auto operator op(std::pair<Tp, Up> lhs, \
const std::pair<Tp, Up> &rhs) { \
return {lhs.first op rhs.first, lhs.second op rhs.second}; \
} \
template <class... Ts> \
constexpr auto operator op(std::tuple<Ts...> const &lhs, \
std::tuple<Ts...> const &rhs) { \
return apply2([](auto &&l, auto &&r) { return l op r; }, lhs, rhs); \
} \
template <class Tp, class Up> \
constexpr std::pair<Tp, Up> &operator op##=(std::pair<Tp, Up> &lhs, \
const std::pair<Tp, Up> &rhs) { \
lhs.first op## = rhs.first; \
lhs.second op## = rhs.second; \
return lhs; \
} \
template <class... Ts> \
constexpr auto operator op##=(std::tuple<Ts...> &lhs, \
const std::tuple<Ts...> &rhs) { \
return lhs = lhs op rhs; \
}
OO_PTEQ_(+)
OO_PTEQ_(-)
OO_PTEQ_(*)
OO_PTEQ_(/)
OO_PTEQ_(%)
OO_PTEQ_(&)
OO_PTEQ_(|)
OO_PTEQ_(^)
OO_PTEQ_(<<)
OO_PTEQ_(>>)
#undef OO_PTEQ_
#undef TPL_SIZE_
template <class Tp, class Up>
std::istream &operator>>(std::istream &is, std::pair<Tp, Up> &p) {
return is >> p.first >> p.second;
}
template <class Tp, class Up>
std::ostream &operator<<(std::ostream &os, const std::pair<Tp, Up> &p) {
return os << p.first << ' ' << p.second;
}
template <typename... Ts>
std::istream &operator>>(std::istream &is, std::tuple<Ts...> &p) {
std::apply([&](Ts &...targs) { ((is >> targs), ...); }, p);
return is;
}
template <typename... Ts>
std::ostream &operator<<(std::ostream &os, const std::tuple<Ts...> &p) {
std::apply(
[&](Ts const &...targs) {
std::size_t n{0};
((os << targs << (++n != sizeof...(Ts) ? " " : "")), ...);
},
p);
return os;
}
template <class Ch,
class Tr,
class Ct,
std::enable_if_t<std::is_same_v<decltype(std::declval<Ct>().begin()),
typename Ct::iterator> &&
std::is_same_v<decltype(std::declval<Ct>().end()),
typename Ct::iterator>> * = nullptr>
std::basic_ostream<Ch, Tr> &operator<<(std::basic_ostream<Ch, Tr> &os,
const Ct &x) {
if (x.begin() == x.end()) return os;
for (auto it = x.begin(); it != x.end() - 1; ++it) os << *it << ' ';
os << x.back();
return os;
}
const u32 OFFSET = 5;
const u32 N = 3e5 + OFFSET;
const u32 M = 1.2e6 + OFFSET;
const i64 INF64 = 0x3f3f3f3f3f3f3f3f;
const pii DIR4[4] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
using namespace std;
struct Edge {
i64 w;
int to, next;
Edge(i64 _w = 0, int _to = 0, int _next = 0): w(_w), to(_to), next(_next) {}
} e[M];
int head[N], cnt_edge;
void addEdge(int x, int y, i64 w = 1) {
e[++cnt_edge] = Edge(w, y, head[x]);
head[x] = cnt_edge;
}
i64 dis[N];
void dijkstra(int s) {
pqg<pair<i64, int>> q;
memset(dis, 0x3f, sizeof(dis));
q.emplace(dis[s] = 0, s);
while (!q.empty()) {
auto [dis_now, now] = q.top();
q.pop();
if (dis[now] < dis_now) continue;
for (int i = head[now], to; i; i = e[i].next)
if (dis[to = e[i].to] > dis[now] + e[i].w)
q.emplace(dis[to] = dis[now] + e[i].w, to);
}
}
auto solve([[maybe_unused]] int t_ = 0) -> void {
int n, m;
cin >> n >> m;
i64 p, q;
cin >> p >> q;
read_container_(vc<string>, maps, n);
int s = n * m;
auto encode = [&](int x, int y) -> int { return x * m + y; };
auto valid = [&](int x, int y) -> bool {
return x >= 0 && x < n && y >= 0 && y < m && maps[x][y] != '#';
};
for_(i, 0, n - 1)
for_(j, 0, m - 1) switch (maps[i][j]) {
case '.': addEdge(s, encode(i, j), 0); break;
case 'L':
if (valid(i - 1, j + 1))
addEdge(encode(i - 1, j + 1), encode(i, j), p);
if (valid(i + 1, j + 1))
addEdge(encode(i + 1, j + 1), encode(i, j), p);
if (valid(i, j + 2)) addEdge(encode(i, j + 2), encode(i, j), q);
break;
case 'R':
if (valid(i - 1, j - 1))
addEdge(encode(i - 1, j - 1), encode(i, j), p);
if (valid(i + 1, j - 1))
addEdge(encode(i + 1, j - 1), encode(i, j), p);
if (valid(i, j - 2)) addEdge(encode(i, j - 2), encode(i, j), q);
break;
case 'U':
if (valid(i + 1, j - 1))
addEdge(encode(i + 1, j - 1), encode(i, j), p);
if (valid(i + 1, j + 1))
addEdge(encode(i + 1, j + 1), encode(i, j), p);
if (valid(i + 2, j)) addEdge(encode(i + 2, j), encode(i, j), q);
break;
case 'D':
if (valid(i - 1, j - 1))
addEdge(encode(i - 1, j - 1), encode(i, j), p);
if (valid(i - 1, j + 1))
addEdge(encode(i - 1, j + 1), encode(i, j), p);
if (valid(i - 2, j)) addEdge(encode(i - 2, j), encode(i, j), q);
break;
default: break;
}
dijkstra(s);
i64 ans = INT64_MAX;
for_(i, 0, n - 1)
for_(j, 0, m - 1)
if (i64 d1 = dis[encode(i, j)]; d1 != INF64)
for (auto &&[di, dj] : DIR4)
if (auto ii = i + di, jj = j + dj; valid(ii, jj))
if (i64 d2 = dis[encode(ii, jj)]; d2 != INF64) chkmin(ans, d1 + d2);
cout << (ans == INT64_MAX ? -1 : ans) << '\n';
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int i_ = 0;
solve(i_);
return 0;
}