Codeforces Round #760 (Div. 3)ABCDEFG

A.Polycarp and Sums of Subsequences

最大值一定是三个数的和,次大值一定是最大的两个数的和,次次大值一定是最大值和次大值的和。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
    int t;
    cin>>t;
    while(t--){
        vector<int>v;
        for( int i=0;i<7;i++){
            int x;
            cin>>x;
            v.push_back(x);
        }
        sort(v.begin(),v.end());
        int x=v.size()-1;
        cout<<v[x]-v[x-1]<<" "<<v[x]-v[x-2]<<" "<<v[x-2]+v[x-1]-v[x]<<endl;
    }
}

B.Missing Bigram

直接构造字符串即可

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
    int t;
    cin>>t;
    while(t--){
        int n;
        cin>>n;
        string ans;
        cin>>ans;
        for( int i=1;i<n-2;i++){
            string s;
            cin>>s;
            if(s[0]==ans[ans.size()-1]){
                ans+=s[1];
            }
            else {
                ans+=s;
            }
        }
        for( int i=ans.size();i<n;i++){
            ans+='b';
        }
        cout<<ans<<endl;
    }
}

C. Paint the Array

找最大公因数,如果存在答案,那么答案一定是奇数列或偶数列的最大公因数,反之不存在答案。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=110;
ll w[N];
int main(){
	int t;
	cin>>t;
	while(t--){
		int n;
		cin>>n;
		for( int i=0;i<n;i++){
			cin>>w[i];
		}
		ll gcd_even=w[0],gcd_odd=w[1];
		for( int  i=0;i<n;i++){
			if(i%2==0){
				gcd_even=__gcd(gcd_even,w[i]);
			}
			else {
				gcd_odd=__gcd(gcd_odd,w[i]);
			}
		}
		int flag=1;
		for( int i=0;i<n;i+=2){
			if(w[i]%gcd_odd==0){
				flag=0;
			}
		}
		if(flag==1){
			cout<<gcd_odd<<endl;
			continue;
		}
		flag=1;
		for( int i=1;i<n;i+=2){
			if(w[i]%gcd_even==0){
				flag=0;
			}
		}
		if(flag==1){
			cout<<gcd_even<<endl;
		}
		else cout<<0<<endl;
	}
	return 0;
}

D. Array and Operations

贪心算法,每次找两个相隔k的数相除。(不能找相邻的数相除,因为两个数相等的话不是最优解)

#include<bits/stdc++.h>
using namespace std;
const int N=100100;
typedef long long ll;
int w[N];
int cmp( int a,int b){
    return a>b;
}
int main(){
    int t;
    cin>>t;
    while(t--){
        int n,k;
        cin>>n>>k;
        for( int i=1;i<=n;i++){
            scanf("%d",&w[i]);
        }
        sort(w+1,w+1+n,cmp);
        k=min(k,n/2);
        ll ans=0;
        for( int i=1;i<=k;i++){
            ans+=w[i+k]/w[i];
        }
        for( int i=k*2+1;i<=n;i++){
            ans+=w[i];
        }
        cout<<ans<<endl;        
    }
    return 0; 
}

E. Singers’ Tour

公式推导。

#include<bits/stdc++.h>
using namespace std;
const int N=200100;
typedef long long ll;
ll w[N];
ll ww[N];
int main(){
    int t,n;
    cin>>t;
    while(t--){
        cin>>n;
        ll sum=0;
        ll cnt=(1+n)*n/2;
        for( int i=0;i<n;i++){
            cin>>w[i];
            sum+=w[i];
        }
        if(sum%cnt!=0){
            cout<<"NO"<<endl;
            continue;
        }
        else sum/=cnt;
        // cout<<sum<<endl;
        for( int i=0;i<n;i++){
            ww[i]=w[i]-w[(i-1+n)%n];
            ww[i]=ww[i]-sum;
            if(ww[i]%n!=0){
                cout<<"NO";
                goto endd;
            }
            ww[i]=-ww[i]/n;
            if(ww[i]<=0){
                cout<<"NO";
                goto endd;
            }
        }
        cout<<"YES"<<endl;
        for( int i=0;i<n;i++){
            printf("%lld ",ww[i] );
        }
        endd:
        cout<<endl;
    }
    return 0; 
}

F. Reverse

bfs搜索,注意要去掉字符串的前缀0,这里直接转为int去0

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
string sa,sb;
ll a,b;
string int_to_string( ll x){
    string res;
    while(x){
        res+=x%2+'0';
        x/=2;
    }
    reverse(res.begin(),res.end());
    return res;
}
ll string_to_int(string s){
    ll res=0;
    for( int i=0;i<s.size();i++){
        res=res*2+s[i]-'0';
    }
    return res;
}
int bfs( ){
    set<ll>se;
    queue<ll>q;
    se.insert(a);
    q.push(a);
    while(!q.empty()){
        ll now=q.front();
        q.pop();
        if(now==b) return 1; 
        string s=int_to_string(now)+"0";
        // cout<<string_to_int(s)<<endl;
        reverse(s.begin(),s.end());
        ll temp=string_to_int(s);
        if(temp>0&&se.find(temp)==se.end()){
            se.insert(temp);
            q.push(temp);
        }
        s=int_to_string(now)+"1";
        reverse(s.begin(),s.end());
        temp=string_to_int(s);
        if(temp>0&&se.find(temp)==se.end()){
            se.insert(temp);
            q.push(temp);
        }
    }
    return 0;
    
}
int main(){
    cin>>a>>b;
    sa=int_to_string(a);
    sb=int_to_string(b);
    if(bfs()==1) cout<<"YES"<<endl;
    else cout<<"NO"<<endl;
    return 0;
}

G. Trader Problem

并查集。
首先将数列a和b放在一起排序,注意要标记元素属于a还是属于b,然后差分,将差和q放在一起排序。
从小到大遍历差分数组,如果元素属于查询,那么存储答案,如果元素不属于查询,那么将两端序列合并。
合并的方法是启发式合并set,将小的set插入到大的set中,并用并查集维护。
这里有两个set数组,其中aset表示已经选择的元素集合,bset表示没有选择的元素的集合,sum表示所有aset中的元素的和。
合并时,先将aset插入aset,bset插入bset,然后比较aset的最小值和bset的最大值,并且更新sum

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=400100;
int a[N],b[N],q[N];
int fa[N];
ll ans[N],sum;
multiset<int>aset[N],bset[N];
struct event{
	int div,type,pos;
	//div表示两个数的差值,type表示数据类型,pos表示原数的位置
};
int find(int x){
	if(fa[x]!=x) fa[x]=find(fa[x]);
	return fa[x];
}
void merge(int a,int b){
	a=find(a),b=find(b);
	if(aset[a].size()+bset[a].size()<aset[b].size()+bset[b].size())
		swap(a,b);
	for( auto it: aset[b])
		aset[a].insert(it);
	for( auto it: bset[b])
		bset[a].insert(it);
	aset[b].clear();
	bset[b].clear();
	while(!bset[a].empty()&&!aset[a].empty()&&*aset[a].begin()<*bset[a].rbegin()){
		sum-=*aset[a].begin();
		sum+=*bset[a].rbegin();
		aset[a].insert(*bset[a].rbegin());
		bset[a].insert(*aset[a].begin());
		aset[a].erase(aset[a].begin());
		bset[a].erase(--bset[a].end());
	}
	fa[b]=a;
		
}
int cmp(event a,event b){
	if(a.div!=b.div)
	return a.div<b.div;
	else return a.type<b.type;
}
int main(){
	int n,m,qq;
	cin>>n>>m>>qq;
	for( int i=0;i<n;i++){
		scanf("%d",&a[i]);
	}
	for( int i=0;i<m;i++){
		scanf("%d",&b[i]);
	}
	for( int i=0;i<qq;i++){
		scanf("%d",&q[i]);
	}
	vector<pair<int,int> >v;
	//1表示已经拿到的,0表示未拿到的
	for( int i=0;i<n;i++) v.push_back(make_pair(a[i],1));
	for( int i=0;i<m;i++) v.push_back(make_pair(b[i],0));
	sort(v.begin(),v.end());
	sum=accumulate(a,a+n,0ll);
	for(int i=0;i<v.size();i++){
		fa[i]=i;
		if(v[i].second) aset[i].insert(v[i].first);
		else bset[i].insert(v[i].first);
	}
	vector<event>ev;
	for( int i=0;i<n+m-1;i++){
		ev.push_back((event){v[i+1].first-v[i].first,0,i});
	}
	for( int i=0;i<qq;i++) ev.push_back((event){q[i],1,i});
	sort(ev.begin(),ev.end(),cmp);
	for( int i=0;i<ev.size();i++){
		if(ev[i].type==0)
			merge(ev[i].pos,ev[i].pos+1);
		else
			ans[ev[i].pos]=sum;
	}
	for( int i=0;i<qq;i++){
		printf("%lld\n",ans[i]);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值