Codeforces Round #769 (Div. 2) A B C D
- 新年后的康复训练,把近几场vp了,题能补的补补掉。
A ABC(800)
思路: 明显 0 0 0或 1 1 1两者中其中一者出现次数大于等于 2 2 2就一定无法重新排列成长度最大为 1 1 1的回文。
- 参考代码:
#include<bits/stdc++.h>
using namespace std;
#define mp make_pair
#define int long long
#define re register int
#define pb emplace_back
#define lowbit(x) (x&-x)
#define fer(i,a,b) for(re i = a ; i <= b ; i ++)
#define der(i,a,b) for(re i = a ; i >= b ; i --)
#define snow ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int gcd(int a,int b){return b?gcd(b,a%b):a;}
int lcm(int a,int b){return a*b/gcd(a,b);}
typedef pair<int,int>PII;
typedef pair<int,string>PIS;
signed main(){
int t;
cin>>t;
while(t--){
int n;
cin>>n;
string s;
cin>>s;
int sum1,sum2;
sum1=sum2=0;
for(int i=0;i<s.size();i++)if(s[i]=='0')sum1++;
else sum2++;
if(sum1>=2||sum2>=2)cout<<"NO"<<endl;
else cout<<"YES"<<endl;
}
return 0;
}
B Roof Construction(1000)
思路: 因为要求所以相邻数的 ⊕ ⊕ ⊕的最大值最小。那么在二进制形式下可以发现,最大的不超过 n n n的 2 x 2^x 2x一定要和 0 0 0相邻才能使得 ⊕ ⊕ ⊕最小,因为剩余的 2 x + 1 2^x+1 2x+1~ n n n之间的数可以通过相邻的放置使得 ⊕ ⊕ ⊕永远小于 2 x 2^x 2x和 0 0 0的 ⊕ ⊕ ⊕值。
- 参考代码:
#include<bits/stdc++.h>
using namespace std;
#define mp make_pair
#define int long long
#define re register int
#define pb emplace_back
#define lowbit(x) (x&-x)
#define fer(i,a,b) for(re i = a ; i <= b ; i ++)
#define der(i,a,b) for(re i = a ; i >= b ; i --)
#define snow ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int gcd(int a,int b){return b?gcd(b,a%b):a;}
int lcm(int a,int b){return a*b/gcd(a,b);}
typedef pair<int,int>PII;
typedef pair<int,string>PIS;
signed main(){
int t;
cin>>t;
while(t--){
int n;
cin>>n;
int x=n-1;
int sum=1;
while(sum<x){
sum*=2;
}
if(sum>x)sum/=2;
for(int i=n-1;i>=sum;i--)cout<<i<<' ';
for(int i=0;i<=sum-1;i++)cout<<i<<' ';
cout<<endl;
}
return 0;
}
C Strange Test(1600)
- Tip:brute force、math
思路: 对于 m e t h o n 3 methon3 methon3有两种选择,一种是不使用 m e t h o n 3 methon3 methon3那么最少的操作次数显然是 b − a b-a b−a,一种是使用 m e t h o n 3 methon3 methon3且最多只会使用一次,因为 a ∣ b a|b a∣b ≥ \ge ≥ b b b,在操作一次 m e t h o n 3 methon3 methon3之后我们剩下的只需操作 m e t h o n 2 methon2 methon2即可。然后通过推公式可得:假设 c c c ≥ \ge ≥ a a a, d d d ≥ \ge ≥ b b b, c c c和 d d d是 a a a和 b b b通过操作 m e t h o n 1 methon1 methon1和 m e t h o n 2 methon2 methon2转变而来,那么我们可得公式: s u m = c − a + d − b + c ∣ d − d + 1 = c + c ∣ d + ( 1 − a − b ) sum=c-a+d-b+c|d-d+1=c+c|d+(1-a-b) sum=c−a+d−b+c∣d−d+1=c+c∣d+(1−a−b),由于 ( 1 − a − b ) (1-a-b) (1−a−b)是 c o n s t a n t constant constant所以我们最终的目标值是使 c + c ∣ d c+c|d c+c∣d最小, c c c的迭代区间为 [ a , b − 1 ] [a,b-1] [a,b−1],因为 c c c ≥ \ge ≥ b b b的话还不如 b − a b-a b−a来的更优。由于 a l l all all b b b ≤ \le ≤ 1 e 6 1e6 1e6所以跑暴力时间复杂度为 O ( b ) O(b) O(b)可以接受。然后每次的 c c c是确定的,为了 c ∣ d c|d c∣d尽可能小,所以我们构造一个 d d d即可( d d d ≥ \ge ≥ b b b)。
1 : I f 1:If 1:If c u r r e n t current current b i t bit bit o f of of c c c i s is is 0 0 0 a n d and and b b b i s is is 1 , 1, 1, s e t set set t h e the the c u r r e n t current current b i t bit bit o f of of d d d t o to to 1. 1. 1.
2 : I f 2:If 2:If c u r r e n t current current b i t bit bit o f of of c c c i s is is 0 0 0 a n d and and b b b i s is is 0 , 0, 0, s e t set set t h e the the c u r r e n t current current b i t bit bit o f of of d d d t o to to 0. 0. 0.
3 : I f 3:If 3:If c u r r e n t current current b i t bit bit o f of of c c c i s is is 1 1 1 a n d and and b b b i s is is 1 , 1, 1, s e t set set t h e the the c u r r e n t current current b i t bit bit o f of of d d d t o to to 1. 1. 1.
4 : I f 4:If 4:If c u r r e n t current current b i t bit bit o f of of c c c i s is is 1 1 1 a n d and and b b b i s is is 0 , 0, 0, s e t set set t h e the the c u r r e n t current current b i t bit bit o f of of d d d t o to to 1 1 1 a n d and and s t o p . stop. stop.
- 参考代码:
#include<bits/stdc++.h>
using namespace std;
#define mp make_pair
#define int long long
#define re register int
#define pb emplace_back
#define lowbit(x) (x&-x)
#define fer(i,a,b) for(re i = a ; i <= b ; i ++)
#define der(i,a,b) for(re i = a ; i >= b ; i --)
#define snow ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int gcd(int a,int b){return b?gcd(b,a%b):a;}
int lcm(int a,int b){return a*b/gcd(a,b);}
typedef pair<int,int>PII;
typedef pair<int,string>PIS;
signed main(){
int t;
cin>>t;
while(t--){
int a,b;
cin>>a>>b;
int ans=b-a;
for(int c=a;c<b;c++){
int d=0;
for(int j=31;j>=0;j--){
if(b>>j&1){
d+=1<<j;
}
else{
if(c>>j&1){
d+=1<<j;
break;
}
}
}
ans=min(ans,c+(c|d)+1-a-b);
}
cout<<ans<<endl;
}
return 0;
}
D New Year Concert(2000)
- Tip: greedy、math、two pointers、sparse table
思路: 很不错的一道题,让我捡起了ST表,之前在 A c w i n g Acwing Acwing学过倍增。但是对于ST表的建立和区间查询的板子还没有学习,这次给一起学了。感觉这道题综合了很多东西。首先如果一个区间内所有数的 g c d gcd gcd等于该区间 r − l + 1 r-l+1 r−l+1那么这个区间是个 b a d bad bad的区间,我们的任务就是找到所有的 b a d bad bad区间,通过最小的更改使得所有的 b a d bad bad的区间消失。因为 a a a的范围非常大,我们可以找一个很大的质数使得该原本 b a d bad bad的区间变成 g o o d good good的区间。然后我们需要在区间内选择一个数将其变成该很大的质数,显然区间的最后一个数是最优的(贪心),因为可能后续有很多的 b a d bad bad区间的 l l l会 ≤ \le ≤当前区间的 r r r,那么更改最后一个,我们可以使得后续的那些 l l l ≤ \le ≤当前区间的 r r r的区间全部变成 g o o d good good区间,这会使得我们最终的操作次数最少。然后区间查询 g c d gcd gcd就套用 S T ST ST表的板子。然后进行处理,有一个很强的性质, g c d gcd gcd会随着区间的变大越来越小, r − l + 1 r-l+1 r−l+1会越来越大。而我们题目要求最终输出是随着 r r r变大的在线区间内最小的更改次数。那么随着 r r r变大如果 g c d ( gcd( gcd(l − - −r ) ) )已经 < < < r − l + 1 r-l+1 r−l+1那么永远无法再找到 g c d ( gcd( gcd(l − - −r ) ) ) = = == == < < < r − l + 1 r-l+1 r−l+1因为前者会越来越小后者会越来越大。我们我们如果碰到 g c d ( gcd( gcd(l − - −r ) ) ) < < < r − l + 1 r-l+1 r−l+1的情况我们需要将 l + + l++ l++直到 g c d ( gcd( gcd(l − - −r ) ) ) ≥ \ge ≥ r − l + 1 r-l+1 r−l+1。
- 参考代码:
#include<bits/stdc++.h>
using namespace std;
#define mp make_pair
#define int long long
#define re register int
#define pb emplace_back
#define lowbit(x) (x&-x)
#define fer(i,a,b) for(re i = a ; i <= b ; i ++)
#define der(i,a,b) for(re i = a ; i >= b ; i --)
#define snow ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int gcd(int a,int b){return b?gcd(b,a%b):a;}
int lcm(int a,int b){return a*b/gcd(a,b);}
typedef pair<int,int>PII;
typedef pair<int,string>PIS;
int n;
const int N=2e5+10;
int a[N];
int st[N][20];
void make_st(){
int k=__lg(n);
for(int i=1;i<=n;i++)st[i][0]=a[i];
for(int i=1;i<=k;i++){
for(int j=1;j+(1<<i)-1<=n;j++){
st[j][i]=gcd(st[j][i-1],st[j+(1<<(i-1))][i-1]);
}
}
}
int query(int l,int r){
int k=__lg(r-l+1);
return gcd(st[l][k],st[r-(1<<k)+1][k]);
}
signed main(){
snow;
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
make_st();
int ans=-1;
int res=0;
int l=1;
for(int r=1;r<=n;r++){
while(l<r&&query(l,r)<r-l+1)l++;
if(query(l,r)==r-l+1){
if(l>ans){
ans=r;
res++;
}
}
cout<<res<<' ';
}
cout<<endl;
return 0;
}