牛客周赛 Round 80【题解未完成 FG】

65 阅读3分钟
题目难度知识点
A 棋盖放子签到
B 训练参赛签到
C 举手赢棋easy思维
D 举手赢棋hard★★思维
E 公平对局★ ★思维
F 怎么写线性SPJ★★构造

棋盖放子

#include<bits/stdc++.h>
using namespace std;
int main(void)
{
    int x,y; cin>>x>>y;
    if(x<y) puts("quit the competition!");
    else cout<<x-y;
    return 0;
}

训练参赛

#include<bits/stdc++.h>
using namespace std;
const int N=1e5*5+10;
typedef long long int LL;
LL a[N],n,sum;
int main(void)
{
    cin>>n;
    for(int i=0;i<n*2;i++) cin>>a[i];
    sort(a,a+n+n);
    for(int i=1;i<n*2;i+=2) sum+=(a[i]-a[i-1]);
    cout<<sum;
    return 0;
}

举手赢棋easy

不满足的情况这里之前的0的位置都是可以填的。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
typedef long long int LL;
int n,flag=1,flag1=1,ans;
string s;
int main(void)
{
    cin>>n>>s;
    int cnt1=0,cnt0=0;
    for(int i=0;i<n;i++)
    {
        if(s[i]=='1') cnt1++;
        if(s[i]=='0') cnt0++;
        if(cnt1<cnt0)
        {
            if(s[i]=='0' && flag ) cnt0--,cnt1++,flag=0,ans=(cnt0+1);
            if(cnt1<cnt0) flag1=0;
        }
    }
    if(flag1)
    {
        if(flag) cout<<n;
        else cout<<ans;
    }else puts("0");
    return 0;
}

举手赢棋hard

image.png 就是分类谈论,注意去重。例如 1,3 和3,1是一种。

#include<bits/stdc++.h>
using namespace std;
typedef long long int LL;
LL n,cnt=2,flag=1;
string s;
int main(void)
{
    cin>>n>>s;
    LL cnt0=0,cnt1=0;
    vector<LL>ve,idx;
    for(int i=0;i<s.size();i++)
    {
        if(s[i]=='1') cnt1++;
        if(s[i]=='0') cnt0++;
        if(cnt0>cnt1)
        {
            if(s[i]=='0' && cnt)
            {
                cnt0--,cnt1++,cnt--;
                if(cnt==1) ve.push_back(cnt0+1);
                else if(cnt==0) ve.push_back(cnt0+2);
                idx.push_back(i);
            }
            if(cnt0>cnt1) flag=0;
        }
    }
    if(flag)
    {
        if(cnt==1)
        {
            cout<<ve[0]*(n-1-idx[0])+ve[0]*(ve[0]-1)/2+ve[0]*(idx[0]+1-ve[0]);
        }
        else if(cnt==2)
        {
            cout<<n*(n-1)/2;
        }
        else if(cnt==0) 
        {
            cout<<ve[0]*(ve[0]-1)/2+ve[0]*(ve[1]-ve[0]);
        }
    }
    else puts("0");
    return 0;
}

公平对局

image.png 根据数据可以看出是O(n^2)左右可以过,但是好像无从下手,我们反过来想是不是从白色点bfs更好,若所有的边界只有一个空白是不是就说明该位置可以放,且包围了所有的白色。这时候可以过125分了,因为有特殊的行情况。

10
..........
.########.
#***#****#
#***#****#
#***.****#
#***#****#
#***#****#
#***#****#
.########.
..........
我们可以发现放一个可以满足2个联通块了,但是我们放的黑棋的位置其实是一个,
故我们将能够满足的白色的个数累加到对应应该放的黑棋的位置就可以了。
#include<bits/stdc++.h>
using namespace std;
const int N=1e3+10;
string s[N];
int n,st[N][N],flag[N][N],anss[N][N],ans;
int dx[4]={-1,0,0,1};
int dy[4]={0,-1,1,0};
void solve(int x,int y)
{
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++) flag[i][j]=0;
    int cnt=1,cnt1=0;
    queue< pair<int,int> >q; q.push({x,y});
    st[x][y]=1;
    int ansx=0,ansy=0;
    while(q.size())
    {
        auto temp=q.front();  q.pop();
        x=temp.first,y=temp.second;
        for(int i=0;i<4;i++)
        {
            int tempx=x+dx[i],tempy=y+dy[i];
            if(tempx<0||tempx>=n||tempy<0||tempy>=n) continue;
            if(st[tempx][tempy]) continue;
            if(s[tempx][tempy]=='.' && !flag[tempx][tempy]) cnt1++,flag[tempx][tempy]=1,ansx=tempx,ansy=tempy;
            else if(s[tempx][tempy]=='*')
            {
                q.push({tempx,tempy});
                st[tempx][tempy]=1;
                cnt++;
            }
        }
    }
    if(cnt1==1){
        anss[ansx][ansy]+=cnt;//累加到要放的棋子那里
        ans=max(ans,anss[ansx][ansy]);
    }
    
}
int main(void)
{
    cin>>n;
    for(int i=0;i<n;i++) cin>>s[i];
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            if(st[i][j]) continue;
            if(s[i][j]=='*') solve(i,j);
        }
    }
    cout<<ans;
    return 0;
}