B. Playing with GCD
题意:给定一个长度为
n
n
n 的数组
a
a
a,判断是否存在一个数组
b
b
b (长度为
n
+
1
n+1
n+1),使得对于
a
i
a_i
ai 的每一项都有
a
i
=
g
c
d
(
b
i
,
b
i
+
1
)
a_i=gcd(b_i,b_{i+1})
ai=gcd(bi,bi+1)。
思路1:参考。因为
a
i
−
1
=
g
c
d
(
b
i
−
1
,
b
i
)
a_{i-1}=gcd(b_{i-1},b_{i})
ai−1=gcd(bi−1,bi),
a
i
+
1
=
g
c
d
(
b
i
+
1
,
b
i
+
2
)
a_{i+1}=gcd(b_{i+1},b_{i+2})
ai+1=gcd(bi+1,bi+2),且,
a
i
=
g
c
d
(
b
i
,
b
i
+
1
)
a_{i}=gcd(b_{i},b_{i+1})
ai=gcd(bi,bi+1),因此,
a
i
a_{i}
ai 要能被
g
c
d
(
a
i
−
1
,
a
i
+
1
)
gcd(a_{i-1},a_{i+1})
gcd(ai−1,ai+1) 整除。
思路2:构造
b
b
b 数组,
b
1
=
a
1
,
b
n
+
1
=
a
n
b_1=a_1, b_{n+1}=a_n
b1=a1,bn+1=an,其他位置的
b
i
=
l
c
m
(
a
i
−
1
,
a
i
)
b_i=lcm(a_{i-1},a_{i})
bi=lcm(ai−1,ai)。判断该
b
b
b 数组是否能还原
a
a
a 数组。证明可以看一下官方题解。
思路1代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+5;
int T,n,a[N];
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>T;
while(T--){
cin>>n;
for(int i=1;i<=n;++i) cin>>a[i];
string ans="YES\n";
for(int i=2;i<n;++i){
if(a[i]%(__gcd(a[i-1],a[i+1]))) ans="NO\n";
}
cout<<ans;
}
}
C1. Good Subarrays (Easy Version)
题意:给定一个长度为
n
n
n 的数组
a
a
a,求有多少对
(
l
,
r
)
,
1
≤
l
≤
r
≤
n
(l,r),1\le l\le r\le n
(l,r),1≤l≤r≤n 是好的。
(
l
,
r
)
(l,r)
(l,r) 表示了
a
l
.
.
.
a
r
a_l...a_r
al...ar 这段元素。定义长度为
m
m
m 的一段序列
b
b
b 是好的,当且仅当,对于每一个
i
i
i,
1
≤
i
≤
m
1\le i \le m
1≤i≤m,
b
i
≥
i
b_i \ge i
bi≥i 。
思路:遍历数组,判断当前位置是否可以作为第
(
l
e
n
+
1
)
(len+1)
(len+1)位,若能,则继续向下遍历,直到某位置上的数不能作为第
(
l
e
n
+
1
)
(len+1)
(len+1)位,累积长度为
l
e
n
len
len的序列对答案的贡献为
l
e
n
∗
(
l
e
n
+
1
)
/
2
len*(len+1)/2
len∗(len+1)/2 ,然后更新
l
e
n
len
len,去找出下一段合法序列,注意,该位置的左边界不一定是该位置,可能更左一些。
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=2e5+5;
int T,n,a[N],b[N];
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>T;
// T=1;
while(T--){
cin>>n;
for(int i=1;i<=n;++i) cin>>a[i];
a[n+1]=0;
if(n==1) cout<<1<<'\n';
else{
int len=1,ans=0;
for(int i=2;i<=n+1;++i){
if(a[i]>len) len++;
else{
ans+=(len*(len+1)/2);
len=min(len,min(i,a[i]));
ans-=(len*(len-1)/2);
}
}
cout<<ans<<'\n';
}
}
}
D. Equal Binary Subsequences
个人觉得这是一道很棒的题!!!
题意:给定一个长度为
2
n
2n
2n 的字符串。要求选一个子序列,操作一次 右循环一个单位。然后判断是否能将串分成两个长度为
n
n
n 的,完全一样的子序列,若不能,输出-1;若能输出选择循环的子序列大小和元素下标,以及其中一个长度为
n
n
n的子序列的下标。
思路:官方题解讲得超好!建议看看官方题解。
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define pb push_back
int T,n;
string s;
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>T;
while(T--){
cin>>n>>s;
int cnt=0;
for(int i=0;i<s.size();++i) if(s[i]=='1') cnt++;
if(cnt%2) cout<<-1<<'\n';
else{
vector<int> v;
for(int i=0;i<s.size();i+=2){
if(s[i]!=s[i+1]){
if(v.size()%2==0) { //取0的下标
if(s[i]=='0') v.pb(i);
else v.pb(i+1);
}
else { //取1的下标
if(s[i]=='1') v.pb(i);
else v.pb(i+1);
}
}
}
cout<<v.size();
for(auto x:v) cout<<' '<<x+1;
cout<<'\n';
for(int i=0;i<s.size();i+=2) cout<<i+1<<' ';
cout<<'\n';
}
}
}