牛客小白月赛74 题解

当时过了点了就没打,现在补上


A. 简单的整除

题面

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int d[4]={2,3,5,7};
int main() {
    ios::sync_with_stdio(false);
    int x;
    cin>>x;
    bool flag=false;
    for(int i=0;i<4;i++)
    {
        if(x%d[i]==0)
        {
            flag=true;
            break;
        }
    }
    if(flag)
        cout<<"YES"<<'\n';
    else
        cout<<"NO"<<'\n';
    return 0;
}

B. 整数划分

题面

肯定是按照1,2,3,...这样下去是最优的,只用关注最后一个的取值就行

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
vector<int>s;
int main() {
    ios::sync_with_stdio(false);
    int T;
    cin>>T;
    while(T--)
    {
        s.clear();
        int n;
        cin>>n;
        int i=1;
        for(i=1;i<=n;i++)
        {
            s.push_back(i);
            n-=i;
        }
        if(i>n)
            s.push_back(n);
        int l=s.size();
        if(s[l-1]<=s[l-2])
        {
            s[l-2]+=s[l-1];
            s.pop_back();
        }
        for(int i=0;i<s.size()-1;i++)
            cout<<s[i]<<' ';
        cout<<s[s.size()-1]<<'\n';
    }
    return 0;
}

C. 传送阵

题面

显然就是统计不同值的格子数

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
map<int,bool>mp;
int main() {
    ios::sync_with_stdio(false);
    int T;
    cin>>T;
    while(T--)
    {
        mp.clear();
        int n,m;
        cin>>n>>m;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                int x;
                cin>>x;
                mp[x]=true;
            }
        }
        cout<<mp.size()<<'\n';
    }
    return 0;
}

D. 修改后的和

题面

每一次操作之后对总和的贡献为

如果选择要对 进行操作,那么从右往左依次操作是最优的,因为先操作左边的会使右边的数变小

综上,只用找出来 最大的几个 就行

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
ll a[N];
int main() {
    ios::sync_with_stdio(false);
    int T;
    cin>>T;
    while(T--)
    {
        int n,m;
        cin>>n>>m;
        ll sum=0;
        vector<ll>s;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
            if(a[i]>0)
                s.push_back(a[i]*(n-i+1));
            sum+=a[i];
        }
        if(s.size()==0)
        {
            cout<<sum<<'\n';
            continue;
        }
        sort(s.begin(),s.end());
        reverse(s.begin(),s.end());
        for(int i=0;i<min(m,(int)s.size());i++)
            sum-=s[i];
        cout<<sum<<'\n';
    }
    return 0;
}

E. 幼稚园的树2

题面

可以发现每棵树的生长是有循环的,计算一下就行

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
int h[N],a[N];
int main() {
    ios::sync_with_stdio(false);
    int T;
    cin>>T;
    while(T--)
    {
        int n,m,k,b;
        cin>>n>>m>>k>>b;
        for(int i=1;i<=n;i++)
            cin>>h[i];
        for(int i=1;i<=n;i++)
            cin>>a[i];
        if(m==1)
        {
            for(int i=1;i<=n;i++)
                cout<<h[i]<<' ';
            cout<<'\n';
            continue;
        }
        for(int i=1;i<=n;i++)
        {
            int st=(k-h[i])/a[i]+1;
            int s=(k-b)/a[i]+1;
            if(st>m-1)
                cout<<h[i]+(m-1)*a[i]<<' ';
            else
                cout<<b+(m-1-st)%s*a[i]<<' ';
        }
        cout<<'\n';
    }
    return 0;
}

F. 最便宜的构建

题面

查询是否连通,可以使用并查集

正着思考不太容易,可以考虑枚举验证,发现枚举验证挺容易,但是复杂度很大。用二分优化

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m,k;
const int N=1e5+5;
struct arc
{
    int a,b,w;
}a[N];
int f[N];
vector<int>q[N];
bool cmp(arc x,arc y){return x.w<y.w;}
int find(int x)
{
    return x==f[x]?x:f[x]=find(f[x]);
}
void merge(int x,int y)
{
    x=find(x);y=find(y);
    if(x!=y)
        f[x]=y;
}
bool judge(int x)
{
    for(int i=1;i<=n;i++)
        f[i]=i;
    for(int i=1;i<=x;i++)
        merge(a[i].a,a[i].b);
    for(int i=1;i<=k;i++)
    {
        int now=find(q[i][0]);
        for(auto x:q[i])
            if(find(x)!=now)
                return false;
    }
    return true;
}
int main() {
    ios::sync_with_stdio(false);
    cin>>n>>m;
    for(int i=1;i<=m;i++)
        cin>>a[i].a>>a[i].b>>a[i].w;
    cin>>k;
    for(int i=1;i<=k;i++)
    {
        int x;
        cin>>x;
        for(int j=1;j<=x;j++)
        {
            int y;
            cin>>y;
            q[i].push_back(y);
        }
    }
    sort(a+1,a+1+m,cmp);
    int l=1,r=m,ans=m;
    while(l<r)
    {
        int mid=(l+r)>>1;
        if(judge(mid))
        {
            ans=mid;
            r=mid;
        }
        else
            l=mid+1;
    }
    cout<<a[ans].w<<'\n';
    return 0;
}

并查集一定要加查找优化,不加会炸,一下午的debug的教训🤡


img_show