Codeforces Round #545 (Div. 2)A B C D前四题题解

太垃圾了,只做得来,前四题,比赛时打得更菜

A. Sushi for Two

本场比赛最良心的题

题意:给你一串1和2组成的数字,要求你求一个最大串的长度,这个最大串必须是1和2的数量相等,并且只能一边是1一边是2,既1和2不能交叉。做法直接把1和2 的数量压缩了,然后直接遍历找到最大值

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;

int a[N],n,ans;
int b[N];
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
    }
    ans=0;
    memset(b,0,sizeof(b));
    int cnt=1;
    b[1]=1;
    for(int i=2;i<=n;i++)
    {
        if(a[i]==a[i-1])
        {
            b[cnt]++;
        }
        else
        {
            //cout<<b[cnt]<<" ";
            b[++cnt]=1;
        }
    }
    //cout<<b[cnt]<<endl;
    for(int i=2;i<=cnt;i++)
    {
        ans=max(ans,2*min(b[i],b[i-1]));
    }
    cout<<ans<<endl;
    return 0;
}

B. Circus

这道题就不怎么良心了,但不过还是怪自己太菜。

题意,给你n个艺术家,有的艺术家可以表演小丑,有的可以表演杂技,有的都可以,有的什么都不可以,要求安排两场演出,每一场上的人数一样,并且第一场表演小丑的人数等于第二次表演杂技的人数。

比赛时以为是特定规律,结果怎么也过不了,后来发现其实是暴力,先把每一种艺术家的人数以及标号记录下来,然后枚举第一次出场的人数,如果枚举三种艺术家,由于最大加起来有5000会卡,但不过由于数据好像不强,把一个循环改成+=2或者+=4可以过,既然枚举三种不行那就枚举只能表演一种技艺的艺术家,然后把两种都可以的艺术家拿去平衡,如果不能就继续,不会随便拿来不位置就可以了。

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int a,b,c,d,n;
char stra[N],strb[N];
int v[4][5010];
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin>>n;
    cin>>stra>>strb;
    a=b=c=d=0;
    for(int i=0; i<n; i++)
    {
        if(stra[i]=='0'&&strb[i]=='0')
            v[0][a++]=i+1;
        else if(stra[i]=='1'&&strb[i]=='0')
            v[1][b++]=i+1;
        else if(stra[i]=='0'&&strb[i]=='1')
            v[2][c++]=i+1;
        else
            v[3][d++]=i+1;
    }
    int flag=0;
    for(int i=0; i<=b; i++)
    {
        if(i>n/2)
            break;
        for(int j=0; j<=c; j++)
        {
            if(i+j>n/2)
                break;
            int x=i,y=c-j;
            int k=y+d-x;
            if(k%2||k<0)
                continue;
            k=k/2;
            if(k>d)
                continue;
            int t=n/2-i-j-k;
            if(t<0||t>a)
                continue;
            int cnt=0;
            for(int l=0; l<i; l++)
                cout<<v[1][l]<<" ",cnt++;
            for(int l=0; l<j; l++)
                cout<<v[2][l]<<" ",cnt++;
            for(int l=0; l<k; l++)
                cout<<v[3][l]<<" ",cnt++;
            for(int l=0; cnt<n/2; l++)
                cout<<v[0][l]<<" ",cnt++;
            flag=1;

            if(flag)
                break;
        }
        if(flag)
            break;
    }
    if(!flag)
        cout<<"-1";
    cout<<endl;
    return 0;
}

C. Skyscrapers

题意就和题上面说的差不多,简单说一下,就是给你一个n*m的数表,到第 i,j个数据,问第i行j列中,找出最小的一个x,使所有的值都在1到x之间,但不过i行j列单独的数据相对位置不变。

做法,吧每一行每一列的数据存储起来离散化,然后遍历数表,分别找到mp[i][j]在i行j列的相对大小,然后和i行j列离散后的数据个数一起处理得到答案,具体看代码。

 

其实我也说不清楚

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n,m,mp[1010][1010];
vector<int>l[1010],r[1010];
int ans[1010][1010];
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            cin>>mp[i][j];
            l[i].push_back(mp[i][j]);
            r[j].push_back(mp[i][j]);
        }
    }
    for(int i=1;i<=n;i++)
    {
        sort(l[i].begin(),l[i].end());
        l[i].erase(unique(l[i].begin(),l[i].end()),l[i].end());
    }
    for(int j=1;j<=m;j++)
    {
        sort(r[j].begin(),r[j].end());
        r[j].erase(unique(r[j].begin(),r[j].end()),r[j].end());
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            int t=mp[i][j],ml=l[i].size(),mr=r[j].size();
            int llow=lower_bound(l[i].begin(),l[i].end(),t)-l[i].begin()+1;
            int rlow=lower_bound(r[j].begin(),r[j].end(),t)-r[j].begin()+1;
            if(llow>=rlow)
                mr=llow-rlow+mr;
            else
                ml=rlow-llow+ml;
            ans[i][j]=max(mr,ml);
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
            cout<<ans[i][j]<<" ";
        cout<<endl;
    }
    return 0;
}

D. Camp Schedule

就是一个kmp算法的应用

题意:给出两个01串 s和t 要求改变s中01的位置,使t串在s中出现次数最多,直接对t求一个next数组,然后统计s中01个数,依次填补,就得到答案,如果匹配一个t就跳next。

#include<bits/stdc++.h>
using namespace std;
const int N = 5e5 + 10;
char a[N],b[N];
int nxt[N];
void getnxt(char s[])
{
    nxt[0]=-1;
    int i=0,j=-1;
    int len=strlen(s);
    while(i<len)
    {
        if(j==-1||s[i]==s[j])
        {
            i++,j++;
            nxt[i]=j;
        }
        else
            j=nxt[j];
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin>>a>>b;
    getnxt(b);
    int x=0,y=0;
    int len=strlen(a);
    for(int i=0;i<len;i++)
    {
        if(a[i]=='0')
            x++;
        else
            y++;
    }
    string ans="";
    int cnt=0;
    len=strlen(b);
    while(x>0&&y>0)
    {
        if(b[cnt]=='0'&&x>0)
            x--,ans+='0';
        if(b[cnt]=='1'&&y>0)
            y--,ans+='1';
        cnt++;
        if(cnt==len)
            cnt=nxt[cnt];
    }
    while(x--)ans+='0';
    while(y--)ans+='1';
    cout<<ans<<endl;
    return 0;
}

后面的题做不来了。。。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值