牛客小白月赛4 【题解完成】

107 阅读5分钟
题目难度知识点
A 三角形★★贪心,指针
B 博弈论★★抽屉原理,字符串
C 病菌感染模拟
D 郊区春游★★floyd,状压DP,TSP
E 浮点数输出签到
F 等价串★★构造
G 黑白棋★★模拟
H 相邻的糖果★★贪心
I 合唱队形★★二分
J 强迫症构造,贪心

三角形

image.png 将其从小到大排,最大的一定是三个连续的,三个指针模拟移动即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long int LL;
typedef pair<LL,LL> PII;
LL n,m;
vector<PII>ve;
int main(void)
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        int x; cin>>x;
        ve.push_back({x,i});
    }
    sort(ve.begin(),ve.end());
    while(m--)
    {
        int op; cin>>op;
        LL a=-1,b=-1,c=-1,flag=0;
        for(int i=ve.size()-1;i>=0;i--)
        {
            if(ve[i].second==op) {
                continue;
            }
            if(a==-1) a=ve[i].first;
            else if(b==-1) b=ve[i].first;
            else if(c==-1) c=ve[i].first;
            if( c!=-1 && a<b+c ) 
            {
                flag=1;
                cout<<a+b+c<<endl;
                break;
            }
            if(c!=-1) a=b,b=c,c=-1;
        }
        if(!flag) cout<<-1<<endl;
    }
    return 0;
}

博弈论

image.png

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int a[N],n,st[N];
int main(void)
{
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int k=1;k<=5;k++)
    {
        for(int i=1;i<=n;i++)
        {
            int l=i,r=i+k-1;
            int sum=0;
            for(int j=l;j<=r;j++) sum=sum*10+a[j];
            if(sum>1e5) continue;
            st[sum]++;
        }
    }
    for(int i=0;i<=1e5;i++)
        if(!st[i])
        {
            cout<<i;
            return 0;
        }
    return 0;
}
#include<bits/stdc++.h>
using namespace std;
int main(void)
{
    int n,x;
    string a;
    cin>>n;
    for(int i=0;i<n;i++) cin>>x,a+=to_string(x);
    for(int i=0;i<=1e4+10;i++)
    {
        if(a.find(to_string(i))==-1)
        {
            cout<<i;
            return 0;
        }
    }
    return 0;
}

病菌感染

image.png

#include<bits/stdc++.h>
using namespace std;
const int N=1010;
int a[N][N],n,m,x,y;
int dx[4]={-1,0,0,1};
int dy[4]={0,-1,1,0};
void solve(int x,int y)
{
    int cnt=0;
    for(int i=0;i<4;i++)
    {
        int tempx=x+dx[i],tempy=dy[i];
        if(tempx<1||tempx>n||tempy<1||tempy>n) continue;
        if(a[tempx][tempy]) cnt++;
    }
    if(cnt>=2) a[x][y]++;
}
int main(void)
{
    cin>>n>>m;
    while(m--) cin>>x>>y,a[x][y]++;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++) solve(i,j);
    int cnt=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            if(a[i][j]) cnt++;
    if(cnt==n*n) puts("YES");
    else puts("NO");
    return 0;
}

郊区春游

image.png 先floyd再状压DP,f[i][j],是i状态且最后的落脚点是j的最小花费。

#include<bits/stdc++.h>
using namespace std;
const int N=220;
int g[N][N],n,m,r;
int f[1<<15][20],a[20];
int main(void)
{
    cin>>n>>m>>r;
    for(int i=0;i<r;i++) cin>>a[i];
    memset(g,0x3f,sizeof g);
    for(int i=1;i<=n;i++) g[i][i]=0;
    while(m--)
    {
        int a,b,c; cin>>a>>b>>c;
        g[a][b]=g[b][a]=min(g[a][b],c);
    }
    for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                    g[i][j]=min(g[i][j],g[i][k]+g[k][j]);
    
    memset(f,0x3f,sizeof f);
    for(int i=0;i<r;i++) f[1<<i][i]=0;
    for(int i=0;i<(1<<r);i++)
    {
        for(int j=0;j<r;j++)
        {
            if(i>>j&1)
            {
                for(int k=0;k<r;k++)
                {
                    if(i>>k&1) 
                    {
                        f[i][j]=min(f[i][j],f[i-(1<<j)][k]+g[a[k]][a[j]]);
                    }
                }
            }
        }
    }
    int ans=1e9;
    for(int i=0;i<r;i++) ans=min(ans,f[(1<<r)-1][i]);
    cout<<ans;
    return 0;
}

浮点数输出

image.png

#include<bits/stdc++.h>
using namespace std;
int main(void)
{
    string s; cin>>s;
    cout<<s;
    return 0;
}

等价串

image.png A->B,反过来B->A,故取一个中间状态都弄成"0"串。

#include<bits/stdc++.h>
using namespace std;
int main(void)
{
    int t; cin>>t;
    while(t--)
    {
        int n,m; cin>>n>>m;
        string a,b; cin>>a>>b;
        string temp1,temp2;
        for(int i=0;i<a.size();i++)
            if(a[i]=='1') temp1+="00";
            else temp1+=a[i];
        for(int i=0;i<b.size();i++)
            if(b[i]=='1') temp2+="00";
            else temp2+=b[i];
        if( (temp1.size()%3) == (temp2.size()%3) ) puts("YES");
        else puts("NO");
    }
    return 0;
}

黑白棋

image.png 在线的黑白棋小游戏

#include<bits/stdc++.h>
using namespace std;
int a[15][15];
int dx[8]={-1,-1,-1,0,0,1,1,1};
int dy[8]={-1,0,1,-1,1,-1,0,1};
int o;
int solve(int x,int y,int o)
{
    int cnt=0;
    for(int d=0;d<8;d++)
    {
        int tempx=x+dx[d],tempy=y+dy[d];
        if(a[tempx][tempy]==-1) continue;
        if(a[tempx][tempy]!=1-o) continue;
        for(int stx=tempx,sty=tempy;;stx+=dx[d],sty+=dy[d])
        {
            if(a[stx][sty]==-1) break;
            if(a[stx][sty]==o)
            {
                for(; (tempx!=stx) || (tempy!=sty) ;tempx+=dx[d],tempy+=dy[d])
                {
                    a[tempx][tempy]=o;
                    cnt++;
                }
                break;
            }
        }
    }
    return cnt;
}
int main(void)
{
    int x,y;
    memset(a,-1,sizeof a);
    a[4][5]=a[5][4]=0;
    a[4][4]=a[5][5]=1;
    while(cin>>x>>y)
    {
        if(solve(x,y,o)) a[x][y]=o,o=o^1;
        else solve(x,y,o^1),a[x][y]=o^1;
    }
    int cnt0=0,cnt1=0;
    
    for(int i=1;i<=8;i++)
        for(int j=1;j<=8;j++)
             if(a[i][j]==0) cnt0++;
             else if(a[i][j]==1) cnt1++;
    printf("%d:%d",cnt0,cnt1);
    return 0;
}

相邻的糖果

image.png 显然一个区间大于x,一定优先从后往前吃多余的糖果。

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
typedef long long int LL;
LL a[N],n,m,x,ans;
int main(void)
{
    cin>>n>>m>>x;
    for(int i=1;i<=n;i++) cin>>a[i];
    LL ans=0,sum=0;
    for(int i=1;i<=n;i++)
    {
        if(i>m) sum-=a[i-m];
        sum+=a[i];
        if(sum>x)
        {
            ans+=(sum-x);
            a[i]=a[i]-(sum-x);
            sum=x;

        }
    }
    cout<<ans;
    return 0;
}

合唱队形

image.png

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
string a;
int s[N],n;
bool check(int x)
{
    for(int i=1;i<=n;i++)
    {
        int l=i,r=i+x-1;
        if(r>n) continue;
        int temp1=s[r]-s[l-1];
        if(temp1==x) return true;
        if(temp1==x-1)
        {
            int temp2=s[l-1];
            int temp3=s[n]-s[r];
            if(temp2||temp3) return true;
        }
    }
    return false;
}
int main(void)
{
    cin>>n>>a;
    a="0"+a;
    for(int i=1;i<+n;i++)
    {
        s[i]=s[i-1];
        if(a[i]=='0') s[i]++;
    }
    int l=0,r=n;
    while(l<r)
    {
        int mid=(l+r+1)/2;
        if(check(mid)) l=mid;
        else r=mid-1;
    }
    cout<<l;
    return 0;
}

强迫症

image.png 重复的数和一个最大的数结合,一定可以构造一个不重复的数,一直这样。 故结果就是重复数的累加和,就是操作次数。

#include<bits/stdc++.h>
using namespace std;
int n,x,cnt;
map<int,int>mp;
int main(void)
{
    cin>>n;
    while(n--)
    {
        cin>>x;
        if(mp.count(x)) cnt++;
        mp[x]++;
    }
    cout<<cnt;
    return 0;
}