Educational Codeforces Round 149 (Rated for Div. 2)

文章提供了几道编程竞赛题目(C.BestBinaryString、D.BracketColoring、E.PlayoffFixing和F.EditorialforTwo)的解决方案,包括代码实现和解题思路。对于C题,重点是减少1之间的0;D题涉及括号颜色的分配;E题是关于比赛淘汰策略的计算问题;F题则是寻找数组子集和满足条件的最小值。
摘要由CSDN通过智能技术生成

C. Best Binary String

看一下例子不难发现

成本最少就是让1与1之间夹的0的次数最少,也就是1?1这种要变1,0?0这种要变0,1?变1,其他情况随意即可,简单推导得出:?前面是什么就变成什么;

代码如下:

#include<iostream>
#include<algorithm>
#include<set>
#include<vector>
#include<queue>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<ctime>
#include<map>
#include<stack>
using namespace std;
#define int long long
const int N=2e5+10;
signed main()
{
    int t;
    cin>>t;
    string s;
    while(t--)
    {
        cin>>s;
        int n=s.size();
        if(s[0]=='?')
        s[0]='0';
        for(int i=1;i<n;++i)
        {
            if(s[i]=='?')
            {
                if(s[i-1]=='1')s[i]='1';
                else s[i]='0';
            }
        }
        cout<<s<<endl;
    } 
    
    return 0; 
}

D. Bracket Coloring

最多只有两种颜色,先判断字符串本身能否成为完美字符,如果可以直接输出1,否则

先把能组成括号对的标成1,剩下的为2就可以了

代码如下:

#include<iostream>
#include<algorithm>
#include<set>
#include<vector>
#include<queue>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<ctime>
#include<map>
#include<stack>
using namespace std;
#define int long long
const int N=2e5+10;
int c[N];
signed main()
{
    int n,t;
    cin>>t;
    string s;
    while(t--)
    {
        cin>>n>>s;
        stack<int>r,v;
        int a=0,b=0;
        for(int i=0;i<n;++i)
        {
            c[i]=0;
            if(s[i]=='(')a++;
            else b++;
        }
        if(a!=b)
        {
            cout<<-1<<endl;
            continue;
        }
        a=b=0;
        int fg=0,ff=0;
        for(int i=n-1;i>=0;--i)
        {
            if(s[i]=='(')r.push(i);
            else if(r.size())
            {
                 r.pop();
            }
            else 
            {
                ff=1;break;
            }
        }
        if(!ff)
        {
            cout<<1<<endl;
            for(int i=0;i<n;++i)cout<<1<<" ";
            cout<<endl;
            continue;
        }
        for(int i=0;i<n;++i)
        {
            if(s[i]=='(')r.push(i);
            else if(r.size())
            {
                fg=1;
                int pos=r.top(); r.pop();
                c[i]=c[pos]=1;
            }
        }
        if(!fg)
        {
            cout<<1<<endl;
            for(int i=0;i<n;++i)
            {
                cout<<1<<" \n"[i==n-1];
            }
            continue;
        }
        else 
        {
            int f=1;
            for(int i=0;i<n;++i)
            {
                if(c[i]!=1)
                {
                    f=2;
                    break;
                }
            }
            cout<<f<<endl;
            for(int i=0;i<n;++i)
            {
                if(c[i]!=1)cout<<2<<" ";
                else cout<<c[i]<<" ";
            }
            cout<<endl;
        }
    } 
    
    return 0; 
}

E. Playoff Fixing

这个题我想了很久,最后看了知乎大佬的代码写的,链接在这Educational Codeforces Round 149 (Rated for Div. 2) A ~ E - 知乎 (zhihu.com)

先捋下题意:ai为-1时表示i位置的数未确定,然后每轮比赛都会淘汰掉一半的人。

这里建议i把它看成变数哈,就是比如a2<a1,然后下一轮,a2就在1的位置上,也就是变成a1

思路:

每轮淘汰的人只能后半数字的人被淘汰,那么淘汰的人是确定的,设这轮未确定的后半数x,那么x个数可以选择放的x个位置就有x!的选择,然后每个被淘汰的数必须各自独立在不同的比赛中,如果该比赛的两个数都是-1,-1,则要×2,设这轮有y个该的比赛,那么该轮的贡献就为x!2^y;

代码如下:

#include <bits/stdc++.h>
#include<vector>
using namespace std;
#define int long long
const int N=2e6+10,mod=998244353;
int p[N];
int ksm(int x,int n)
{
    int sum=1;
    int a=x;
    while(n)
    {
        if(n&1)sum=sum*a%mod;
        a=a*a%mod;
        n>>=1;
    }
    return sum%mod;
}
void init()
{
    p[0]=1;
    for(int i=1;i<=2e6;++i)
    {
        
        p[i]=p[i-1]*i%mod;
    }
}
int solve(int n, vector <int> a)
{
    
    if(n==0)return 1;
    vector<int>b(1,0);
    int y=0,x=(1ll<<(n-1));
    for(int i=1;i<=(1ll<<n);i+=2)
    {
        
        if(a[i]>a[i+1])swap(a[i],a[i+1]);
        if(a[i]==-1&&a[i+1]==-1)
        {
            ++y;
            b.push_back(-1);
        }
        else if(a[i]==-1)
        {
            if(a[i+1]<=(1<<(n-1)))
            {
                
                b.push_back(a[i+1]);
            }
            else
            {
                x--;
                b.push_back(-1);
            }
        }
        else if(a[i]>(1<<(n-1)))
        {
            return 0;
        }
        else if(a[i+1]<=(1<<(n-1)))return 0;
        else 
        {
            x--;
            b.push_back(a[i]);
        }
    }
    return p[x]*ksm(2,y)%mod*solve(n-1,b)%mod;
}
signed main()
{
    int k;
    init();
      cin>>k;
      vector<int>a((1<<k)+10);
      for(int i=1;i<=(1<<k);++i)cin>>a[i];
      int xx=solve(k,a);
      cout<<xx;
}

F. Editorial for Two

这个题是看知乎的大佬写的,发现思路居然这么简单!链接在这

Educational Codeforces Round 149 (Rated for Div. 2) A - F - 知乎 (zhihu.com)

思路:

用二分写个函数ck,然后在里面写个循环找i左右两边选的数,两边的个数尽可能选大,最后只要相加>=k就行了

#include<iostream>
using namespace std;
#include<vector>
#include<queue>
#define int long long
const int N=2e6+10;
int n,a[N],k;
bool ck(int x)
{
    priority_queue<int>r1,r2;
    vector<int>c(n+1);
    int sum=0;for(int i=1;i<=n;++i)
    {
        r1.push(a[i]);
        sum+=a[i];
        while(sum>x&&r1.size())
        {
            sum-=r1.top();
            r1.pop();
        }
        c[i]=r1.size();
    }
    if(c[n]>=k)return true;
    sum=0;
    for(int i=n;i>=1;--i)
    {
        r2.push(a[i]);
        sum+=a[i];
        while(sum>x&&r2.size())
        {
            sum-=r2.top();
            r2.pop();
        }
        if(r2.size()+c[i-1]>=k)return true;
    }
    return false;
}
signed main()
{
    int t;
    cin>>t;
    while(t--)
    {
        cin>>n>>k;
        int ans=0;
        for(int i=1;i<=n;++i)
        {
            cin>>a[i];
            ans+=a[i];
        }
        int l=1,r=ans;
        while(l<r)
        {
            int mid=(l+r)/2;
            if(ck(mid))
            {
                r=mid;
            }
            else l=mid+1;
        }
        cout<<r<<endl;
    }
    return 0;
}

第一次补完div2的题,在这里留个纪念记录一下,希望有一天我自己能在比赛中写完这些题。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值