T1
中文题意:
T组输入,每次输入一个n,构造长度为n的序列,保证序列中的每一个子序列都是好的。关于好数组的定义是,数组内元素和可以被长度整除。
T
≤
100
,
n
≤
100
T\leq100,n\leq100
T≤100,n≤100。
比较基础的构造题,打印 n n n个 1 1 1或者 n n n个 n n n都可以。
int main() {
int T = 1;
T = read();
while (T--) {
int n = read();
for (int i = 1; i <= n; ++i) printf("%d%c", n, " \n"[i == n]);
}
return 0;
}
T2
中文题意:
T组输入,每组输入给出数组长度n,第二行给出这个数组元素
a
i
a_i
ai,问是不是存在两个不重合的区间,使得
∑
i
=
l
1
r
1
2
a
i
=
∑
j
=
l
2
r
2
2
a
j
\sum\limits_{i=l_1}^{r_1}2^{a_i}=\sum\limits_{j=l_2}^{r_2}2^{a_j}
i=l1∑r12ai=j=l2∑r22aj。
T
≤
100
,
n
≤
1000
,
a
i
≤
1
0
9
T\leq100,n\leq1000,a_i\leq10^9
T≤100,n≤1000,ai≤109。
拿到二进制的关键性质,只有同位为1才会进位。那么我们要找到两个区间使得二进制值相等,那么一定是长度越短越好,长度长了之后还要考虑更多的位数反而更不可能相等,只要存在两个一样的 a i a_i ai,那么我们左右端点分别覆盖这两个相同的数即可。如果不存在两个相同的数,说明这些数转换二进制表示,不存在同为1的位置,那么再累加之后也不可能相等。
bool solve() {
unordered_map<ll, int> mp;
int n = read();
for (int i = 1; i <= n; ++i) ++mp[read()];
for (auto& it : mp) {
if (it.second >= 2) return true;
}
return false;
}
int main() {
int T = 1;
T = read();
while (T--) {
if (solve()) puts("YES");
else puts("NO");
}
return 0;
}
T3
中文题意:
T组输入,给出棋盘大小
n
∗
m
n*m
n∗m,以及每个点的权值,你可以进行的操作是每个点权值加一,或者不动。现在要你随意输出一个新的棋盘,但是要保证棋盘每一个点的上下左右四个点和它的权值不能相等。
T
≤
10
,
1
≤
n
,
m
≤
100
,
a
i
,
j
≤
1
0
9
T\leq10,1\leq n,m \leq100,a_{i,j}\leq 10^9
T≤10,1≤n,m≤100,ai,j≤109
题目给的是机器人打理,并没有说到棋盘两字,如果联想到国际棋盘这个题目将会非常简单。联想棋盘的黑白点,保证相邻点奇偶不一致即可。
const int N = 100 + 7;
int a[N][N];
int main() {
int T = 1;
T = read();
while (T--) {
int n = read(), m = read();
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j) {
a[i][j] = read();
if ((i + j) & 1) { // 想成棋盘,奇数格子为奇偶中的一种,偶数为另外一种
if (a[i][j] & 1) a[i][j] += 1;
}
else {
if ((a[i][j] & 1) == 0) a[i][j] += 1;
}
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
printf("%d%c", a[i][j], " \n"[j == m]);
}
return 0;
}
T4
给出长度为n的数组,每次你可以进行的操作是选择
i
,
j
,
k
i,j,k
i,j,k三个下标位置进行异或,并且用异或之后的值替换掉之前这个位置的值,你可以操作任意次数,如果最终可以调整到n个数变成同一个值输出YES,并且给出你选择的调整的步数以及每次调整的那3个位置,如果不能调整到同一个值,输出NO。
3
≤
n
≤
1
0
5
,
a
i
≤
1
0
9
3\leq n \leq10^5,a_i\leq10^9
3≤n≤105,ai≤109。
分情况讨论,因为题目涉及的异或操作那么我们需要知道
a
⊕
a
=
0
,
a
⊕
0
=
a
a \oplus a =0, a\oplus0=a
a⊕a=0,a⊕0=a。
如果我们把n分为奇偶两种情况。
1、当n为奇数的时候。我们每次选择
{
1
,
2
,
3
}
,
{
3
,
4
,
5
}
,
{
5
,
6
,
7
}
.
.
.
\{1,2,3\},\{3,4,5\},\{5,6,7\}...
{1,2,3},{3,4,5},{5,6,7}...这样异或下去你会发现最后一组就变成全部数异或的和了。那么接下来,我们再选择
{
1
,
2
,
n
}
,
{
3
,
4
,
n
}
.
.
.
\{1,2,n\},\{3,4,n\}...
{1,2,n},{3,4,n}...这样就可以把全部的数都变成全部数异或的和了!
2、当n为偶数的时候。首先如果我们按照奇数处理,我们一定可以把前n-1个数变成前n-1个数的异或值,这个时候就要判断最后一个数是不是等于前面n-1个数的异或值了,如果是说明存在解,否则就是不存在解的情况。为什么呢?举n=4为例子,你永远都不可能把他们四个都变成
a
1
⊕
a
2
⊕
a
3
⊕
a
4
a_1\oplus a_2\oplus a_3 \oplus a_4
a1⊕a2⊕a3⊕a4的值,因为你能选择的只有3个数,但是异或两个相同的数又变成0了。那么变成6个数也是一样的。永远会有一个多出来的数。
int main() {
int T = 1;
//T = read();
while (T--) {
int n = read();
int sum = 0;
for (int i = 1; i <= n; ++i) a[i] = read(), sum ^= a[i];
if (n & 1) {
puts("YES");
int cnt = n / 2 * 2 - 1;
print(cnt);
for (int i = 1; i < n; i += 2)
printf("%d %d %d\n", i, i + 1, i + 2);
for (int i = 1; i < n - 2; i += 2)
printf("%d %d %d\n", i, i + 1, n);
}
else {
sum ^= a[n];
if (sum != a[n]) puts("NO");
else {
puts("YES");
--n;
int cnt = n / 2 * 2 - 1;
print(cnt);
for (int i = 1; i < n; i += 2)
printf("%d %d %d\n", i, i + 1, i + 2);
for (int i = 1; i < n - 2; i += 2)
printf("%d %d %d\n", i, i + 1, n);
}
}
}
return 0;
}
T5
给你一个长度为n的序列,问你里面又几个子序列,满足子序列的
a
l
⊕
a
r
=
∑
i
=
l
+
1
r
−
1
a
i
a_l\oplus a_r=\sum\limits_{i=l+1}^{r-1}a_i
al⊕ar=i=l+1∑r−1ai。
n
≤
2
∗
1
0
5
,
a
i
≤
2
30
n\leq2*10^5,a_i\leq2^{30}
n≤2∗105,ai≤230。
第一步暴力枚举方法,枚举左右端点时间复杂度通过前缀和处理会到
O
(
n
2
)
O(n^2)
O(n2)。显然会炸时间。但是我们想想是不是不会存在那么多可行的区间呢。
因为我们知道异或的性质,
a
⊕
b
<
a
+
b
a\oplus b < a+b
a⊕b<a+b,那么应该不可能存在那么多合法的很长很长的区间。当然这里只是猜想,我们下面就要去找减少暴力枚举的方法了。
第二步尝试减少枚举次数,如果我们固定了左端点l,并且假设
a
l
>
a
r
a_l>a_r
al>ar,那么我们就可以找到左端点的二进制最高位k,求合过程中,如果大于等于了
2
k
+
1
2^{k+1}
2k+1,说明这个左端点就没用了。你再加数,异或之后也达不到你要的值了。那么再反向遍历,固定一下右端点,假设
a
r
>
a
l
a_r>a_l
ar>al,找到
a
r
a_r
ar的最高二进制位k,又可以找到一些新的区间,但是可能和前面区间重复,记得去重。
但是现在粗略看时间复杂度还是
O
(
n
2
)
O(n^2)
O(n2)因为遍历的
r
r
r还可能走到底。但是是不是一定每一个都走到底呢?答案是否定的。证明如下。假设最高位是k的下标编号有
b
1
,
b
2
,
b
3
.
.
.
b_1,b_2,b_3...
b1,b2,b3...,那么如果我们枚举l在
b
1
b_1
b1的位置,我们枚举的r是不可能超过
b
3
b_3
b3的位置的,一旦超过了
b
3
b_3
b3这个位置,就会存在
a
b
2
+
a
b
3
≥
2
k
+
1
a_{b_2}+a_{b_3} \geq 2^{k+1}
ab2+ab3≥2k+1了,无法满足上方的要求。那么总的枚举次数就是
∑
b
i
+
2
−
b
i
\sum b_{i+2}-b_i
∑bi+2−bi,这个的时间复杂度是不会超过O(n)的,那么带上我们求每一个点的最高二进制位时间,那么本题的时间复杂度就是
O
(
n
l
o
g
a
i
)
O(nlog_{a_i})
O(nlogai)
const int N = 1e6 + 7;
ll n, m;
ll a[N];
void solve() {
n = read();
rep(i, 1, n) a[i] = read();
set<pai> st;
for (int i = 1; i < n; ++i) {
ll sum = 0;
int x = log2(a[i]);
for (int j = i + 2; j <= n; ++j) {
sum += a[j - 1];
if (sum >= (1 << (x + 1))) break;
if (sum == (a[i] ^ a[j])) st.insert({ i,j });
}
}
for (int i = n; i > 1; --i) {
ll sum = 0;
int x = log2(a[i]);
for (int j = i - 2; j; --j) {
sum += a[j + 1];
if (sum >= (1 << (x + 1))) break;
if (sum == (a[i] ^ a[j])) st.insert({ j,i });
}
}
print(st.size());
}