Acwing 第 82 场周赛

比赛链接:登录 - AcWing

A题:

签到

#include<iostream>
#include<algorithm>
using namespace std;

struct rule
{
    bool operator()(const int a,const int b)const{
        return a>b;
    }
};

int main()
{
    int n,k;
    int a[1005];
    cin>>n>>k;
    for(int i=0;i<n;++i)
    {
        cin>>a[i];
    }
    sort(a,a+n,rule());
    cout<<a[k-1];
    return 0;
}

B题:

模拟:

1.第一个倒得牌子为向左倒,则左边那些都倒。

2.最后一个牌子向右倒,则右边那些都倒。

3.向左倒牌子和向右倒牌子中间的牌子都不倒。

4.向右倒和向左倒牌子中间的牌子,若为奇数个,则留一个不倒;若为偶数个,则都倒。

(比赛时没有看到左右倒是相间的,写非常恶心)

#include<iostream>
using namespace std;

int main()
{
    int n;
    cin>>n;

    char ch[3005];
    cin>>ch+1;

    int cnt=0;
    int ans=0;
    int dir=0;
    int LR=0;
    int l,r;

    for(int i=1;i<=n;++i)
    {
        if(dir==0&&ch[i]=='R')
        {
            l=i;
            dir=1;
            ans+=cnt;
            cnt=0;
            dir=1;
        }
        else if(dir==1&&ch[i]=='L')
        {
            r=i;
            if((r-l)%2==0) ans++;
            dir=0;
        }

        if(dir==0) cnt++;
        
        if(dir==0&&ch[i]=='L')
        {
            cnt=0;
        }
        
        if(i==n&&ch[i]!='L')
        {
            ans+=cnt;
        }
    }

    cout<<ans<<endl;

    return 0;
}

重构后:

#include<iostream>
using namespace std;

int main()
{
    int n;
    char ch[3005];
    int ans=0,cnt=0;
    int pos=-1;
    
    cin>>n;
    cin>>ch;
    
    //搜索最后一个要倒得牌子是向左倒还是向右倒
    int last=-1;
    for(int i=n-1;i>=0;i--)
    {
        if(ch[i]=='L') 
        {
            last=1;
            break;
        }
        else if(ch[i]=='R') 
        {
            last=2;
            break;
        }
    }
    
    //对整个多米诺骨牌遍历
    for(int i=0;i<n;++i)
    {
        //如果这个牌子不倒,那么当前牌子到上一个倒了的牌子之间不倒牌子个数加1
        if(ch[i]=='.') cnt++;
        
        //如果向右倒,那么他前面不倒的牌子是真不倒,加到ans中,并且记录这组向右倒得牌子的编号
        if(ch[i]=='R')
        {
            pos=i;
            ans+=cnt;
        }
        //如果向左倒,那么他前面不倒的牌子将被他推倒,并判断这段最中间的牌子是否能保住
        else if(ch[i]=='L')
        {
            if((i-pos)%2==0&&pos!=-1) ans++;
            cnt=0;
        }
    }
    
    //如果最后一个牌子不是向右倒,那么最后一段的牌子不倒,加到ans中
    if(last!=2) ans+=cnt;
    
    cout<<ans<<endl;
    
    return 0;
}

C题:

先思考什么情况不能构成规定的序列,无非有两种

第一种:0太多

第二种:1太多

那么,0最多的极限是什么呢?如010/0101010。可以看出,0最多比1多一个。

那么,1最多的极限是什么呢?如11011、11011011。可以看出,一个0可以间隔两个1,即1最多是0的2倍多2个。

即当 m>2*n+2 或者 n>m+1 ,不能构成序列。

接下来构造序列,构造方法为,若1比0多,则优先输出1,形成类似110110110的序列。

如果1跟0一样多,甚至1少于0,则优先输出0,形成类似01010101的序列。

原因:防止出现3个0,4个1,输出110110最后一个0无法安放。所以要先将0和1剩余个数搞到差不多了,再0101相间输出,可以保证构造的队列有效。

#include<iostream>
using namespace std;

typedef long long ll;

int main()
{
    int n,m;
    cin>>n>>m;

    ll len=n+m;
    int one=0,zero=0;
    int sum_one=0,sum_zero=0;

    if(m>2*n+2||n>m+1) cout<<"-1"<<endl;
    else for(int i=1;i<=len;++i)
    {
        if(2*(n-sum_zero)>=m-sum_one)
        {
            if(one<2&&sum_one!=m)
            {
                cout<<"1";
                zero=0;
                one++;
                sum_one++;
            }
            else if(zero==0&&sum_zero!=n)
            {
                cout<<"0";
                one=0;
                zero++;
                sum_zero++;
            }
        }
        else
        {
            if(zero==0&&sum_zero!=n)
            {
                cout<<"0";
                one=0;
                zero++;
                sum_zero++;
            }
            else if(one<2&&sum_one!=m)
            {
                cout<<"1";
                zero=0;
                one++;
                sum_one++;
            }
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值