Codeforces Round #636 (Div. 3)【ABCDE】(题解)

涵盖知识点:思维、贪心、图论、差分。

比赛链接:传送门

A - Candies

题意: 给定一个等式\(x + 2x + 4x + ... + 2^{k-1}x = n\),其中\(n\)给定,要求输出一个\(k>1\)时满足该等式的一个\(x\)
题解: 暴力枚举每个\(k\)
Accept Code:

#include <bits/stdc++.h>
using namespace std;
int main(){
    int t;cin>>t;
    while(t--){
        int n;
        cin>>n;
        for(int i=4;i<=n+1;i<<=1){
            if(n%(i-1)==0){
                cout<<n/(i-1)<<"\n";
                break;
            }
        }
    }
    return 0;
}

B - Balanced Array

题意: 构造长度为偶数\(n\)的数列要求所有数字全都不相同,前一半为偶数,后一半为奇数。且前一半的和等于后一半的和。
题解: 非4倍数无解,否则偶数按顺序排列,前\(\frac{n}{4}\)个奇数位对应的偶数减\(1\),后面的对应偶数加\(1\)
Accept Code:

#include <bits/stdc++.h>
using namespace std;
int main(){
    int t;cin>>t;
    while(t--){
        int n;
        cin>>n;
        if(n%4){
            cout<<"NO\n";
            continue;
        }
        cout<<"YES\n";
        for(int i=1;i<=n/2;i++)cout<<i*2<<" ";
        for(int i=1;i<=n/4;i++)cout<<i*2-1<<" ";
        for(int i=n/4+1;i<=n/2;i++)cout<<i*2+1<<" ";
        cout<<"\n";
    }
    return 0;
}

C - Alternating Subsequence

题意: 求最长的正负相间子序列的最大和。
题解: 贪心选取每个符号相同区间的最大值加起来即可。
Accept Code:

#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+10,inf=1e9+10;
int a[maxn];
typedef long long ll;
int main(){
    int t;cin>>t;
    while(t--){
        int n;
        cin>>n;
        for(int i=1;i<=n;i++)cin>>a[i];
        int flag=a[1]/abs(a[1]);
        ll ans=0;
        for(int i=1;i<=n;i++){
            int mx=-inf,j;
            for(j=i;j<=n&&a[j]/abs(a[j])==flag;j++)mx=max(mx,a[j]);
            ans+=mx;
            i=j-1;
            flag=-flag;
        }
        cout<<ans<<"\n";
    }
    return 0;
}

D - Constant Palindrome Sum

题意: 每次操作可以将任意数字变为区间\([1,k]\)内的任意数字。要求数列所有左右对称的下标和相加相等。问最少操作次数。
题解: 枚举\([2,2k]\)内的所有值。将操作次数差分一下即可线性算出。
Accept Code:

#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+10,inf=1e9+10;
int a[maxn];
typedef long long ll;
int main(){
    int t;cin>>t;
    while(t--){
        int n;
        cin>>n;
        for(int i=1;i<=n;i++)cin>>a[i];
        int flag=a[1]/abs(a[1]);
        ll ans=0;
        for(int i=1;i<=n;i++){
            int mx=-inf,j;
            for(j=i;j<=n&&a[j]/abs(a[j])==flag;j++)mx=max(mx,a[j]);
            ans+=mx;
            i=j-1;
            flag=-flag;
        }
        cout<<ans<<"\n";
    }
    return 0;
}

E - Weights Distributing

题意: 给一个\(n\)个点和\(m\)条边的无向图以及三个节点\(a、b、c\),给定\(m\)个权值\(p_m\),要求给出一种分案权值的方案使\(a->b->c\)的最短路权重之和最小。
题解: 观察两个样例就可以发现:\(a、b、c\)三个点要么通过一个中间节点相连,或者三者直接成一条直线,所以最短路\(a->x->b->x->c\),对于第二种情况\(x=b\)也成立,那么只需要算出每个节点到\(a、b、c\)三者的最短路,将权值\(p_m\)升序排序,因为dis(b,x)dis(b,x)走了两次,将最短的分给\(b−x\)路径,其余的分给\(a-x\)\(c-x\)即可,枚举每个节点,求最小值。前缀和加速处理一下。
Accept Code:

#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
typedef long long ll;
const ll inf=1e18;
ll n,m,a,b,c,p[maxn];
ll dis[3][maxn];
vector<ll> edg[maxn];
void bfs(int st,int idx){
    queue<int> q;
    q.push(st);
    dis[idx][st]=0;
    while(!q.empty()){
        int u=q.front();
        q.pop();
        for(auto v:edg[u]){
            if(dis[idx][v]>dis[idx][u]+1){
                dis[idx][v]=dis[idx][u]+1;
                q.push(v);
            }
        }
    }
}
int main(){
    int t;cin>>t;
    while(t--){
        cin>>n>>m>>a>>b>>c;
        for(int i=0;i<=n;i++)edg[i].clear(),dis[0][i]=dis[1][i]=dis[2][i]=inf;
        for(int i=1;i<=m;i++)cin>>p[i];
        sort(p+1,p+m+1);
        for(int i=1,u,v;i<=m;i++){
            p[i]+=p[i-1];
            cin>>u>>v;
            edg[u].push_back(v);
            edg[v].push_back(u);
        }
        bfs(a,0),bfs(b,1),bfs(c,2);
        ll ans=inf;
        for(int i=1;i<=n;i++){
            if(dis[0][i]+dis[1][i]+dis[2][i]>m)continue;
            ans=min(ans,p[dis[1][i]]+p[dis[0][i]+dis[1][i]+dis[2][i]]);
        }
        cout<<ans<<"\n";
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/charles1999/p/12751671.html
今日推荐