Codeforces Round #682 (Div. 2)
传送门(点击传送)
A. Specific Tastes of Andre
题意:
定义如果一个数组如果这个数组的所有元素之和可以整除这个数组的元素个数,那么称这个数组为好数组,现在给出数组元素个数 n ,请构造这个数组,每个元素不小于 1 且不大于 100。( t 组数据)
思路:
直接构造所有元素都是 1 即可。
代码:
#include<bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int t,n;
cin>>t;
while(t--){
cin>>n;
for(int i=1;i<=n;i++){
cout<<1<<" ";
}
cout<<endl;
}
return 0;
}
B. Valerii Against Everyone
题意:
现在给出一个 n 个元素的序列 b,设每个元素为
b
i
b_i
bi,并且有对应的序列 a ,有对应关系
a
i
=
2
b
i
a_i=2^{b_i}
ai=2bi,现在问是否有符合条件的区间
[
l
1
,
r
1
]
[l_1,r_1]
[l1,r1]和
[
l
2
,
r
2
]
[l_2,r_2]
[l2,r2],满足在 a 上的区间和相等,且有
l
1
⩽
r
1
<
l
2
⩽
r
2
l_1\leqslant r_1< l_2\leqslant r_2
l1⩽r1<l2⩽r2。( t 组数据)
思路:
对于
2
X
1
+
2
X
2
+
.
.
.
+
2
X
k
2^{X_1}+2^{X_2}+...+2^{X_k}
2X1+2X2+...+2Xk 与
2
Y
1
+
2
Y
2
+
.
.
.
+
2
Y
l
2^{Y_1}+2^{Y_2}+...+2^{Y_l}
2Y1+2Y2+...+2Yl ,若
X
1
,
X
2
,
.
.
.
X
k
X_1,X_2,...X_k
X1,X2,...Xk两两不等且
Y
1
,
Y
2
,
.
.
.
Y
l
Y_1,Y_2,...Y_l
Y1,Y2,...Yl两两不等,那么两个式子必然不等。对于 2 的幂次方,一定有两个相同的元素才能构成等式成立。然而只要有两个相同的元素,那么就必定存在两个区间使得区间和相同(这时区间长度就为1,连个区间分别是这个相等的元素)。所以本体思路即找序列中是否有相等元素即可。
代码:
#include<bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int t,n,get_num;
cin>>t;
while(t--){
cin>>n;
bool flag=false;
unordered_set<int>unset;
for(int i=1;i<=n;i++){
cin>>get_num;
if(unset.find(get_num)!=unset.end()) flag=true;
unset.insert(get_num);
}
if(flag) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}
C. Engineer Artem
题意:
有一个 n 排 m 列的矩阵 a ,给出矩阵每个元素
a
i
,
j
a_{i,j}
ai,j,现在让构造矩阵 b 。且
b
i
,
j
b_{i,j}
bi,j可以取
a
i
,
j
a_{i,j}
ai,j,也可以取
a
i
,
j
+
1
a_{i,j}+1
ai,j+1,请构造出矩阵 b 使得矩阵 b 相邻的元素都不相等。
思路:
构造题,思路为把矩阵看作国际象棋的棋盘,保证所有黑色格子的元素为奇数,所有白色格子的元素为偶数即可。
代码:
#include<bits/stdc++.h>
using namespace std;
int num[105][105];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int t,n,m;
cin>>t;
while(t--){
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>num[i][j];
if((i+j)%2){
if(num[i][j]%2==0) num[i][j]++;
}else{
if(num[i][j]%2==1) num[i][j]++;
}
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cout<<num[i][j]<<" ";
}
cout<<endl;
}
}
return 0;
}
D. Powerful Ksenia
题意:
有一个 n 个元素的序列 a ,现在你可以进行如下操作,每次操作可以选
i
,
j
,
k
i,j,k
i,j,k 并让
a
i
,
a
j
,
a
k
a_i,a_j,a_k
ai,aj,ak都等于
a
i
⨁
a
j
⨁
a
k
a_i\bigoplus a_j\bigoplus a_k
ai⨁aj⨁ak(
⨁
\bigoplus
⨁为按位异或),问能否进行至多 n 次操作使得序列的所有元素都相等。
思路:
首先,我们有以下式子
x
⨁
y
⨁
y
=
x
x\bigoplus y\bigoplus y=x
x⨁y⨁y=x ,我们可以让3个元素中相等的两个元素变为另一个元素。所以对于元素个数为奇数个的序列一定是可以的,因为我们可以通过操作1、2、3, 1、4、5,… ,1、n-1、n 这种操作让2和3相等,4和5相等,… ,n-1和n相等。之后再进行一次1、2、3, 1、4、5,… ,1、n-1、n的操作就可以让所有元素都跟元素位置为1的元素相等,总共n-1次操作。对于元素个数为偶数个的序列,我们这么操作就需要最后多余出的一个元素等于我们前面这种操作下来的值,我们操作过后有
a
1
,
a
1
,
a
1
,
.
.
.
a
1
,
a
n
a_1,a_1,a_1,...a_1,a_n
a1,a1,a1,...a1,an我们要让这个
a
n
a_n
an刚好等于我们的
a
1
a_1
a1,那么如何判断呢,我们之前是
a
1
⨁
a
2
⨁
a
3
a_1\bigoplus a_2\bigoplus a_3
a1⨁a2⨁a3,再用产生的结果
a
1
a_1
a1去进行
a
1
⨁
a
4
⨁
a
5
a_1\bigoplus a_4\bigoplus a_5
a1⨁a4⨁a5,相当于初始序列的
a
1
⨁
a
2
⨁
a
3
⨁
a
4
⨁
a
5
a_1\bigoplus a_2\bigoplus a_3\bigoplus a_4\bigoplus a_5
a1⨁a2⨁a3⨁a4⨁a5这么一个累积异或,所以我们进行到最后的
a
1
⨁
a
n
−
1
⨁
a
n
a_1\bigoplus a_{n-1}\bigoplus a_n
a1⨁an−1⨁an就相当于从
a
1
a_1
a1一直异或到
a
n
−
1
a_{n-1}
an−1所以我们只需要判断从从
a
1
a_1
a1一直异或到
a
n
−
1
a_{n-1}
an−1的结果知否等于
a
n
a_n
an即可,即(
a
1
⨁
a
2
⨁
a
3
⨁
.
.
.
⨁
a
n
a_1\bigoplus a_2\bigoplus a_3\bigoplus ...\bigoplus a_n
a1⨁a2⨁a3⨁...⨁an是否为 0 )。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int num[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>num[i];
}
if(n%2){
cout<<"YES"<<endl<<n-1<<endl;
for(int i=2;i<=n;i+=2){
cout<<"1 "<<i<<" "<<i+1<<endl;
}
for(int i=2;i<=n;i+=2){
cout<<"1 "<<i<<" "<<i+1<<endl;
}
}else{
int xor_n=0;
for(int i=1;i<=n;i++) xor_n^=num[i];
if(xor_n==0){
cout<<"YES"<<endl<<n-2<<endl;
for(int i=2;i<n;i+=2){
cout<<"1 "<<i<<" "<<i+1<<endl;
}
for(int i=2;i<n;i+=2){
cout<<"1 "<<i<<" "<<i+1<<endl;
}
}else{
cout<<"NO"<<endl;
}
}
return 0;
}
E. Yurii Can Do Everything
题意:
有一个序列 a ,问有多少个区间
[
i
,
j
]
[i,j]
[i,j] 满足
a
i
⨁
a
j
=
a
i
+
1
+
a
i
+
2
+
.
.
.
+
a
j
−
2
+
a
j
−
1
a_i\bigoplus a_j=a_{i+1}+a_{i+2}+...+a_{j-2}+a_{j-1}
ai⨁aj=ai+1+ai+2+...+aj−2+aj−1。
思路:
假设我们
m
a
x
(
a
i
,
a
j
)
max(a_i,a_j)
max(ai,aj)的二进制最高位为 k ,那么我们就一定有
a
i
+
1
+
a
i
+
2
+
.
.
.
+
a
j
−
2
+
a
j
−
1
<
2
k
+
1
a_{i+1}+a_{i+2}+...+a_{j-2}+a_{j-1}<2^{k+1}
ai+1+ai+2+...+aj−2+aj−1<2k+1(因为
a
i
a_i
ai和
a
j
a_j
aj的异或值不会超过
m
a
x
(
a
i
,
a
j
)
max(a_i,a_j)
max(ai,aj)的二进制位数)。所以 ①我们先假设
a
i
>
a
j
a_i>a_j
ai>aj,算得
a
i
a_i
ai的二进制最高位为 k ,然后从左向右枚举 i ,对于每一个 i ,都去向右一边枚举 j 一边判断是否符合题意直到
2
k
+
1
<
a
i
+
1
+
a
i
+
2
+
.
.
.
+
a
j
−
2
+
a
j
−
1
2^{k+1}<a_{i+1}+a_{i+2}+...+a_{j-2}+a_{j-1}
2k+1<ai+1+ai+2+...+aj−2+aj−1为止。之后 ②我们再假设
a
i
<
a
j
a_i<a_j
ai<aj算得
a
j
a_j
aj的二进制最高位为k,然后从右向左枚举 j ,对于每一个 j ,都去向左一遍枚举 i 一边判断是否符合题意直到
2
k
+
1
<
a
i
+
1
+
a
i
+
2
+
.
.
.
+
a
j
−
2
+
a
j
−
1
2^{k+1}<a_{i+1}+a_{i+2}+...+a_{j-2}+a_{j-1}
2k+1<ai+1+ai+2+...+aj−2+aj−1为止。①②两次计算可能有重复值,去重即可。
接下来证明一下为什么这么看似暴力的做法时间不会 t ,首先你可能会觉得这样暴力不是
n
2
n^2
n2的复杂度吗,那么让我们看一下
n
2
n^2
n2复杂度需要满足什么条件。
2
A
1
>
2
k
+
1
>
A
2
+
A
3
+
.
.
.
+
A
n
2A_1>2^{k+1}>A_2+A_3+...+A_n
2A1>2k+1>A2+A3+...+An后面我们都会把
2
k
+
1
2^{k+1}
2k+1省略掉,有
2
A
2
>
A
3
+
A
4
+
.
.
.
+
A
n
2A_2>A_3+A_4+...+A_n
2A2>A3+A4+...+An,
2
A
3
>
A
4
+
A
5
+
.
.
.
+
A
n
2A_3>A_4+A_5+...+A_n
2A3>A4+A5+...+An,…,
2
A
n
−
1
>
A
n
2A_{n-1}>A_n
2An−1>An,下面我们反着推回去。
2
A
n
−
1
>
A
n
⇒
A
n
−
1
>
1
2
A
n
2A_{n-1}>A_n\Rightarrow A_{n-1} > \frac{1}{2}A_n
2An−1>An⇒An−1>21An
2
A
n
−
2
>
A
n
−
1
+
A
n
>
1
2
A
n
+
A
n
⇒
A
n
−
2
>
3
4
A
n
2A_{n-2}>A_{n-1}+A_{n}>\frac{1}{2}A_n+A_n\Rightarrow A_{n-2}>\frac{3}{4}A_n
2An−2>An−1+An>21An+An⇒An−2>43An
2
A
n
−
3
>
A
n
−
2
+
A
n
−
1
+
A
n
>
3
4
A
n
+
1
2
A
n
+
A
n
⇒
A
n
−
3
>
9
8
A
n
2A_{n-3}>A_{n-2}+A_{n-1}+A_n>\frac{3}{4}A_n+\frac{1}{2}A_n+A_n\Rightarrow A_{n-3}>\frac{9}{8}A_n
2An−3>An−2+An−1+An>43An+21An+An⇒An−3>89An
…
A
1
>
1
2
∗
(
3
2
)
n
−
2
A
n
A_1>\frac{1}{2}*(\frac{3}{2})^{n-2}A_n
A1>21∗(23)n−2An,
又因为
A
1
<
2
30
A_1<2^{30}
A1<230,假设
A
n
A_n
An为1的话实际也不会有多少项,所以对于每一个外层循环的位置 i 或 j ,内循环的枚举是log级的时间复杂度。所以我们整体的时间复杂度为
O
(
n
∗
l
o
g
a
i
)
O(n*log{a_i})
O(n∗logai)。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+10;
int num[N];
ll sum[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
unordered_set<ll>unset;
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>num[i];
sum[i]=sum[i-1]+1LL*num[i];
}
for(int i=1;i<=n;i++){
int limit=num[i],k=0;
while(limit){
k++;
limit>>=1;
}
limit=1<<k;
for(int j=i+2;j<=n;j++){
int x=num[i]^num[j];
if(sum[j-1]-sum[i]==(ll)x){
ll sign=1LL*i*1000000+1LL*j;
unset.insert(sign);
}
if(sum[j-1]-sum[i]>=limit) break;
}
}
for(int j=n;j>=1;j--){
int limit=num[j],k=0;
while(limit){
k++;
limit>>=1;
}
limit=1<<k;
for(int i=j-2;i>=1;i--){
int x=num[i]^num[j];
if(sum[j-1]-sum[i]==(ll)x){
ll sign=1LL*i*1000000+1LL*j;
unset.insert(sign);
}
if(sum[j-1]-sum[i]>=limit) break;
}
}
cout<<unset.size()<<endl;
return 0;
}