Codeforces Round #529 (Div. 3)(全部题解)

A. Repeating Cipher

题意:

将一个字符串S的第一个字符写一次,第二个写两次,第三个写三次......得到字符串t,给你t,求S

分析:

根据规则,t的第一个,第二个,第四个,第七个,第十一个......便是S的组成

代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
    string s;
    int n;
    cin>>n>>s;
    int k = 0;
    for(int i=0;i<n;k++)
    {
        cout<<s[i];
        i += k;
    }
    return 0;
}

B. Array Stabilization

题意:

从数组中删除一个值,求数组中(最大-最小的值)最小是多少

分析:

要么删最大,要么删最小

代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 2e5+55;
int a[N];
int main()
{
    int n;
    cin>>n;
    for(int i=0;i<n;++i)
        cin>>a[i];
    sort(a,a+n);
    int b = a[n-1]-a[1];
    int c = a[n-2]-a[0];
    cout<<min(b,c);
    return 0;
}

C. Powers Of Two

题意:

问一个数 n 能否分成k个2^x形式的数的和

分析:

观察n的二进制下有m个1,那么最少就需要m个,最多无非是n个1相加,k>m时就需要拆分,2^x = 2^(x-1)+2^(x-1),多了一个,所以只要k属于[m,n],就一定可以拆分成k个

代码:

#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 2e5+55;
int a[N];
vector<int> v;
int main()
{
    int n,k;
    cin>>n>>k;
    int sum1 = 0;
    for(int i=0; i<31; ++i)
    {
        if(n&(1<<i))
        {
            sum1++;
            v.push_back((1<<i));
        }
    }
    if(k>=sum1&&k<=n)
    {
        cout<<"YES"<<endl;
        int i = 0;
        while(v.size()<k)
        {
            if(v[i]>1)
            {
                v[i] = v[i]/2;
                v.push_back(v[i]);
            }
            else i++;
        }
        for(int i=0; i<v.size(); ++i)
            printf("%d ",v[i]);
    }
    else cout<<"NO";
    return 0;
}

D. Circular Dance

题意:

n个人围成一圈,每个人记得他的后面两个人是谁,输出每个人站的位置

分析:

注意:不确定后面两个人顺序,ai_1不一定就挨着第i个人

代码:


#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 2e5+55;
int p[N][2];
int vis[N];
void dfs(int x)
{
    if(!vis[x])
    {
        cout<<x<<" ";
        vis[x] = 1;
        int f = p[x][0];
        int s = p[x][1];
        if(vis[f]) dfs(s);
        else if(vis[s]) dfs(f);
        else
        {
            if(p[f][0]==s||p[f][1]==s) //f后面有s,那s一定挨着x
                dfs(f);
            else dfs(s);
        }
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int a,b,n;
    cin>>n;
    for(int i=1; i<=n; ++i)
        cin>>p[i][0]>>p[i][1];
    dfs(1);
    return 0;
}

E. Almost Regular Bracket Sequence

题意:

给你一串括号序列,你可以改变一个位置的括号使得序列合法,求有多少个这样的位置

分析:

用栈来去掉合法的序列,讨论最后栈里剩下的情况

代码:

#include <stack>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e6+66;
char ss[N];
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    stack<int> s;
    int n;
    cin>>n;
    for(int i=1;i<=n;++i)
    {
        cin>>ss[i];
        if(ss[i]==')')
        {
            if(!s.empty()&&ss[s.top()]=='(') s.pop();
            else s.push(i);
        }
        else s.push(i);
    }
    if(s.size()==0||n%2||s.size()>2) cout<<0;//很显然
    else
    {
        int a = s.top();s.pop();
        int b = s.top();
        if(ss[b]==')')
        {
            if(ss[a]==')')  //b位置左边的)都可以改变
            {
                int ans = 0;
                for(int i=1;i<=b;++i)
                    if(ss[i]==')') ans++;
                cout<<ans;
            }
            else cout<<0;// )( 这种无论改变哪一个都不行
        }
        else
        {
            int ans = 0;
            for(int i=a;i<=n;++i) //a位置右边的都可以改变
                if(ss[i]=='(') ans++;
            cout<<ans;
        }
    }
    return 0;
}

F. Make It Connected

题意:

有n个点,每个点有一个权值,在两个点之间连一条边的花费为两点权值之和,还有m条特殊边,加入这条边的花费为w,问使图联通最少花费多少

分析:

使图联通且花费最少,无非是建一颗最小生成树,除了已知的m条边,我们还可以建n*(n-1)/2条边(每两个点一条边),但n很大,建了也存不下,考虑一个点和图联通,它的最小花费一定是和最小权值的点连一条边,于是我们就缩减到了n-1条边,克鲁斯卡尔跑一遍最小生成树就OK了

代码

#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
#define mk make_pair
#define f first
#define s second
using namespace std;
typedef long long ll;
const int MAXN = 2e5+255;
struct node
{
    int u,v;
    ll w;
};
node e[MAXN<<1];  
pair<int,ll> p[MAXN];
bool cmp(pair<int,ll> p1,pair<int,ll> p2)
{
    return p1.s<p2.s;
}
bool cmp2(node e1,node e2)
{
    return e1.w<e2.w;
}
int pre[MAXN];
void init(int n)
{
    for(int i=0;i<=n;++i)
        pre[i] = i;
}
int Find(int x)    //并查集
{
    int t = x;
    while(pre[t]!=t) t = pre[t];
    while(x!=pre[x])
    {
        int tep = pre[x];
        pre[x] = t;
        x = tep;
    }
    return t;
}
bool Mix(int x,int y)
{
    int Fx = Find(x);
    int Fy = Find(y);
    if(Fx!=Fy)
    {
        pre[Fy] = Fx;
        return true;
    }
    return false;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int n,m;
    ll v;
    cin>>n>>m;
    for(int i=1;i<=n;++i)
    {
        cin>>v;
        p[i-1] = mk(i,v);
    }
    int len = 0;
    while(m--)     
    {
        cin>>e[len].v>>e[len].u;
        cin>>e[len++].w;
    }
    sort(p,p+n,cmp);
    for(int i=1;i<n;++i)  //创建n-1条边
    {
        e[len].u = p[0].f;
        e[len].v = p[i].f;
        e[len++].w = p[0].s+p[i].s;
    }
    sort(e,e+len,cmp2);
    init(n);
    int num = n-1;ll ans = 0;
    for(int i=0;i<len&&num;++i)  //Kruskal算法
    {
        if(Mix(e[i].v,e[i].u))
        {
            ans += e[i].w;
            num--;
        }
    }
    cout<<ans;
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值