Codeforces Round #760 (Div.3) A~F

本文解析了Codeforces Round #760 (Div.3) 中的五道编程题,涉及数组操作、数列分析、字符串处理和数学逻辑。通过实例展示了如何运用递推、搜索和数论思想解决问题,适合算法入门者和提高技巧。
摘要由CSDN通过智能技术生成

Codeforces Round #760 (Div.3)

  • 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 m1个,求符合条件的原字符串

思路:如果相邻两个字符的头尾相同就拼上去,不同就直接加上下一个字符,最后如果字符串长度小于 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=nk 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 2ai分钟, ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ······ ,在第 ( ( 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+n2)modn+1)个城镇音乐会的持续时间将是 n ⋅ a i n⋅a_i nai分钟。

给定一个数组 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+na2+(n1)a3++3an1+2anbi=ia1++ai++(i+2)an1+(i+1)anbn=na1+(n1)a2+(n3)a3+2an1+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++n1+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+1bi=ainai+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)2bi(bi+1bi)

**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 0i<n即可,要判断 2 ∗ ∑ b i 2*\sum b_i 2bi是否整除 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)2bi(bi+1bi)是否大于 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,y1018),问能否通过若干次操作后将 x x x变成 y y y

思路:每次操作有两种选择: + 0 +0 +0就是直接翻转; + 1 +1 +1就是 x ∗ 2 + 1 x*2+1 x2+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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学不会数据库

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值