- A. Polycarp and Sums of Subsequences
题目大意:集合 a a a中有三个元素, a a a中元素组合后的和,构成了不含空集的七个元素的集合 b b b,集合 b b b按升序排列,现在给出 b b b,求 a a a
思路: b [ 1 ] , b [ 2 ] b[1],b[2] b[1],b[2]肯定存在于 a a a,显然第三个值肯定是最大的 b [ 7 ] − b [ 1 ] − b [ 2 ] b[7]-b[1]-b[2] b[7]−b[1]−b[2]
Code:
#include <bits/stdc++.h>
using namespace std;
const int N=1e6+10;
typedef long long ll;
int t;
int a[N];
int main(){
cin>>t;
while(t--){
for(int i=1;i<=7;i++) cin>>a[i];
int res1=a[1],res2=a[2],res3;
for(int i=3;i<=7;i++){
if((a[i]+res1+res2)==a[7]){
res3=a[i];
break;
}
}
cout<<res1<<" "<<res2<<" "<<res3<<endl;
}
return 0;
}
- B. Missing Bigram
题目大意:给出一个全为 a / b a/b a/b组成的长度为 n n n的字符串 s t r str str,现在取出所有相邻的 m m m个二元字符,现在给出其中 m − 1 m-1 m−1个,求符合条件的原字符串
思路:如果相邻两个字符的头尾相同就拼上去,不同就直接加上下一个字符,最后如果字符串长度小于 n n n,加上 a / b a/b a/b即可
Code:
#include <bits/stdc++.h>
using namespace std;
const int N=1e6+10;
typedef long long ll;
int t,n;
char a[N][5];
int main(){
cin>>t;
while(t--){
cin>>n;
for(int i=0;i<(n-2);i++){
for(int j=0;j<2;j++){
cin>>a[i][j];
}
}
string s;
s+=a[0];
for(int i=1;i<(n-2);i++){
if(a[i][0]!=a[i-1][1]) s+=a[i];
else s+=a[i][1];
}
if(s.size()<n) s+='a';
cout<<s<<endl;
}
return 0;
}
- C. Paint the Array
题目大意:给定一个数组 a a a,求是否存在一个 d d d,使得 a i a_i ai能整除 d d d且 a i + 1 a_{i+1} ai+1就不能整除
思路:求一个奇数位的 g c d gcd gcd,判断所有偶数位是否都不整除 g c d gcd gcd,如果不成立,就再求一下偶数位 g c d gcd gcd,判断所有奇数位是否都不整除 g c d gcd gcd,都不成立即输出 0 0 0
Code:
#include <bits/stdc++.h>
using namespace std;
const int N=1e6+10;
typedef long long ll;
int t,n;
ll a[N];
ll gcd(ll a,ll b){
if(!b) return a;
return gcd(b,a%b);
}
int main(){
cin>>t;
while(t--){
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
ll gcd1,gcd2;
int flag=1,flag2=1;
gcd1=a[1];
for(int i=1;i<=n;i+=2){
gcd1=gcd(a[i],gcd1);
}
for(int i=2;i<=n;i+=2){
if(a[i]%gcd1==0){
flag=0;
break;
}
}
if(flag){
cout<<gcd1<<endl;
flag2=0;
flag=0;
}
if(flag2){
flag=1;
gcd2=a[2];
for(int i=2;i<=n;i+=2){
gcd2=gcd(a[i],gcd2);
}
for(int i=1;i<=n;i+=2){
if(a[i]%gcd2==0){
flag=0;
break;
}
}
}
if(flag) cout<<gcd2<<endl;
else if(flag2) cout<<"0"<<endl;
}
return 0;
}
- D. Array and Operations
题目大意:给定一个数组 a a a, k k k次操作,每次取出两个数 a i a_i ai, a j a_j aj,记 r e s + = a i / a j res+=a_i/a_j res+=ai/aj,操作结束后, r e s res res加上数组中剩余数的和,求 m i n r e s min_{res} minres
思路:先将数组
a
a
a排序一下,显然
a
i
<
a
j
a_i<a_j
ai<aj时,
r
e
s
res
res值不变是最优选择。我们可以发现
对于
k
k
k次操作,我们取
l
=
n
−
k
l=n-k
l=n−k,
r
=
n
r=n
r=n,
l
,
r
l,r
l,r每次前移时是最优解
Code:
#include <bits/stdc++.h>
using namespace std;
const int N=1e6+10;
typedef long long ll;
int t,n,k;
int a[N];
int main(){
cin>>t;
while(t--){
cin>>n>>k;
for(int i=1;i<=n;i++) cin>>a[i];
ll ans=0;
sort(a+1,a+1+n);
int l=n-k,r=n;
while(k--){
ans=ans+(a[l]/a[r]);
a[r]=0;
a[l]=0;
l--;
r--;
}
for(int i=1;i<=n;i++) ans+=a[i];
cout<<ans<<endl;
}
return 0;
}
- E. Singers’ Tour
题目大意:有 n n n个小镇围成一个环,在第 i i i个小镇有一个歌手 i i i和持续时间为 a i a_i ai的曲子,每位歌手按顺时针走遍这 n n n个小镇,在每个城镇恰好举办一场音乐会。此外,在每个城镇,第 i i i位歌手都受到启发,想出了一首持续 a i a_i ai分钟的歌曲。 这首歌被添加到他的曲目中,以便他可以在其他城市演出。
因此,对于第 i i i个歌手,在第 i i i个城镇的音乐会将持续 a i a_i ai分钟,在第 ( i + 1 ) (i+1) (i+1)个城镇的音乐会将持续 2 ⋅ a i 2⋅a_i 2⋅ai分钟, ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ······ ⋅⋅⋅⋅⋅⋅,在第 ( ( i + k ) m o d n + 1 ) ((i+k)modn+1) ((i+k)modn+1)个城镇音乐会的持续时间将是 ( k + 2 ) ⋅ a i (k+2)⋅a_i (k+2)⋅ai, ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ······ ⋅⋅⋅⋅⋅⋅,在这个城镇 ( ( i + n − 2 ) m o d n + 1 ) ((i+n−2)modn+1) ((i+n−2)modn+1)个城镇音乐会的持续时间将是 n ⋅ a i n⋅a_i n⋅ai分钟。
给定一个数组 b b b,其中 b i b_i bi是第 i i i个城镇中音乐会的总持续时间。求是否存在数组 a a a满足条件。
思路:有条件我们可以列出一个线性方程组:
{
b
1
=
a
1
+
n
∗
a
2
+
(
n
−
1
)
∗
a
3
+
⋅
⋅
⋅
+
3
∗
a
n
−
1
+
2
∗
a
n
⋅
⋅
⋅
⋅
⋅
⋅
b
i
=
i
∗
a
1
+
⋅
⋅
⋅
+
a
i
+
⋅
⋅
⋅
+
(
i
+
2
)
∗
a
n
−
1
+
(
i
+
1
)
∗
a
n
⋅
⋅
⋅
⋅
⋅
⋅
b
n
=
n
∗
a
1
+
(
n
−
1
)
∗
a
2
+
(
n
−
3
)
∗
a
3
⋅
⋅
⋅
+
2
∗
a
n
−
1
+
a
n
\begin{cases} b_1=a_1+n*a_2+(n-1)*a_3+···+3*a_{n-1}+2*a_n\\ \qquad\qquad\qquad\qquad\qquad······\\ b_i=i*a_1+···+a_i+···+(i+2)*a_{n-1}+(i+1)*a_n\\ \qquad\qquad\qquad\qquad\qquad······\\ b_n=n*a_1+(n-1)*a_2+(n-3)*a_3···+2*a_{n-1}+a_n \end{cases}
⎩⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎧b1=a1+n∗a2+(n−1)∗a3+⋅⋅⋅+3∗an−1+2∗an⋅⋅⋅⋅⋅⋅bi=i∗a1+⋅⋅⋅+ai+⋅⋅⋅+(i+2)∗an−1+(i+1)∗an⋅⋅⋅⋅⋅⋅bn=n∗a1+(n−1)∗a2+(n−3)∗a3⋅⋅⋅+2∗an−1+an
n
n
n个柿子相加得:
∑
b
i
=
(
1
+
2
+
⋅
⋅
⋅
+
n
−
1
+
n
)
∗
∑
a
i
=
n
∗
(
n
+
1
)
2
∗
∑
a
i
\sum b_i=(1+2+···+n-1+n)*\sum a_i=\frac{n*(n+1)}{2}*\sum a_i
∑bi=(1+2+⋅⋅⋅+n−1+n)∗∑ai=2n∗(n+1)∗∑ai
又有: b i + 1 − b i = ∑ a i − n ∗ a i + 1 b_{i+1}-b_i=\sum a_i-n*a_{i+1} bi+1−bi=∑ai−n∗ai+1
两式联立可得: a i + 1 = 2 n ∗ ( n + 1 ) ∗ ∑ b i − ( b i + 1 − b i ) n a_{i+1}=\frac{\frac{2}{n*(n+1)}*\sum b_i-(b_{i+1}-b_i)}{n} ai+1=nn∗(n+1)2∗∑bi−(bi+1−bi)
**PS:**得到 a i + 1 a_{i+1} ai+1的通项后注意:记 b 0 = b n b_0=b_n b0=bn,这样遍历 0 ≤ i < n 0\le i\lt n 0≤i<n即可,要判断 2 ∗ ∑ b i 2*\sum b_i 2∗∑bi是否整除 n ∗ ( n + 1 ) n*(n+1) n∗(n+1),判断 2 n ∗ ( n + 1 ) ∗ ∑ b i − ( b i + 1 − b i ) \frac{2}{n*(n+1)}*\sum b_i-(b_{i+1}-b_i) n∗(n+1)2∗∑bi−(bi+1−bi)是否大于 0 0 0且整除 n n n
Code:
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
typedef long long ll;
ll t,n,b[N],a[N];
int main(){
cin>>t;
while(t--){
cin>>n;
int flag=1;
ll sum=0;
for(int i=1;i<=n;i++) {
cin>>b[i];
sum+=b[i];
}
if((sum*2)%(n*n+n)!=0) flag=0;
sum=sum*2/(n*n+n);
b[0]=b[n];
for(int i=0;i<n;i++){
ll tt=sum-(b[i+1]-b[i]);
if(tt<=0||tt%n!=0) {
flag=0;
break;
}
a[i+1]=tt/n;
}
if(!flag) cout<<"NO"<<endl;
else {
cout<<"YES"<<endl;
for(int i=1;i<=n;i++) cout<<a[i]<<" ";
cout<<endl;
}
}
return 0;
}
- F. Reverse
对于一个二进制数
x
x
x,每次操作可以在它的末尾加一个
0
0
0或者
1
1
1,然后将其翻转(自动去除前导
0
0
0)
现在给定两个正整数
x
x
x和
y
y
y,
(
x
,
y
≤
1
0
18
)
\ (x,y\le 10^{18})
(x,y≤1018),问能否通过若干次操作后将
x
x
x变成
y
y
y
思路:每次操作有两种选择: + 0 +0 +0就是直接翻转; + 1 +1 +1就是 x ∗ 2 + 1 x*2+1 x∗2+1再翻转,肯定要通过 d f s / b f s dfs/bfs dfs/bfs搜索来解决,用一个 m a p map map来记录中间值是否已经出现过即可
Code:
d f s dfs dfs:
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
typedef long long ll;
ll x,y;
int flag;
map<ll,int> vis;
int get_bit(ll x){
int res=0;
for(;x;x>>=1) res++;
return res;
}
ll rev(ll x){
ll res=0;
for(;x;x>>=1) res=(res<<1)+(x&1);
return res;
}
void dfs(ll x){
vis[x]=1;
if(x==y) flag=1;
ll tt1=rev(x);
ll tt2=rev(x*2+1);
if(!vis[tt1]&&get_bit(tt1)<=get_bit(y)) dfs(tt1);
if(!vis[tt2]&&get_bit(tt2)<=get_bit(y)) dfs(tt2);
}
int main(){
cin>>x>>y;
flag=0;
dfs(x);
if(!flag)cout<<"NO"<<endl;
else cout<<"YES"<<endl;
return 0;
}
b f s bfs bfs:
#include <bits/stdc++.h>
#define ll long long
using namespace std;
template<class T>
inline void read(T &x){
x=0; char c; int sign=1;
do{ c=getchar(); if(c=='-') sign=-1;}while(!isdigit(c));
do{ x=x*10+c-'0',c=getchar();}while(isdigit(c));
x*=sign;
}
int get_bit(ll x){
int ret=0;
for(;x;x>>=1,ret++);
return ret;
}
ll Rev(ll x){
ll ret=0;
for(;x;x>>=1) ret=(ret<<1)+(x&1);
return ret;
}
ll xx,yy;
int main(){
read(xx),read(yy);
queue<ll> q;
map<ll,int> vis;
int des=get_bit(yy);
q.push(xx);
q.push(Rev(xx));
bool flag=0;
while(q.size()){
ll now=q.front(),revn;
revn=Rev(now);
int cnt=get_bit(now);
q.pop();
if(cnt<des&&vis.count(now)==0) q.push(Rev(now<<1|1));
if(cnt<des&&vis.count(revn)==0) q.push(Rev(revn<<1|1));
if(cnt==des) flag|=(now==yy||revn==yy);
vis[now]=1;
}
if(flag) puts("YES");
else puts("NO");
return 0;
}