牛客小白月赛 30

A题

并查集或者最小生成树

//并查集
#include<iostream>
#include<cstdio>
#include<math.h>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=2e+5;
int f[maxn];
struct node
{
    int x;int y;int w;
}e[maxn];
bool cmp(node a,node b)
{
    return a.w<b.w;
}
void init(int n)
{
    for(int i=1;i<=n;i++)
    {
        f[i]=i;
    }
}
int find(int x)
{
    if(f[x]==x)
        return x;
    else
        return f[x]=find(f[x]);
}
int main()
{
    int n,m;
    cin>>n>>m;
    int x,y,z;
    init(n);
    for(int i=1;i<=m;i++)
    {
        cin>>x>>y>>z;
        e[i].x=x;
        e[i].y=y;
        e[i].w=z;
    }
    sort(e+1,e+m+1,cmp);
    int cnt1=0,cnt2=0;
    for(int i=1;i<=m;i++)
    {
        int rx=find(e[i].x);
        int ry=find(e[i].y);
        if(rx!=ry)
        {
            cnt1++;
            f[rx]=ry;
            if(e[i].w==1)
            {
                cnt2++;
            }
            if(cnt1==n-1)
            {
                break;
            }
        }
    }
    if(cnt1==n-1)
        cout<<cnt2;
    else
        cout<<-1;
}

B题

线段树

#include<iostream>
#include<cstdio>
#include<math.h>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=2e5+5;
struct node
{
	int l,r;
	int maxx,cnt;
}t[maxn<<2];
int w[maxn];
void pushup(int rt)
{
	if(t[rt<<1].maxx==t[rt<<1|1].maxx)
	{
		t[rt].maxx=t[rt<<1].maxx;
		t[rt].cnt=t[rt<<1].cnt+t[rt<<1|1].cnt;
	}
	else
	{
		if(t[rt<<1].maxx>t[rt<<1|1].maxx)
		{
			t[rt].maxx=t[rt<<1].maxx;
			t[rt].cnt=t[rt<<1].cnt;
		}
		else
		{
			t[rt].maxx=t[rt<<1|1].maxx;
			t[rt].cnt=t[rt<<1|1].cnt;
		}
	}
}
void build(int u,int l,int r)
{
	t[u].l=l,t[u].r=r;
	if(l==r)
	{
		t[u].cnt=1;
		t[u].maxx=w[l];
		return ;
	}
	int mid=(l+r)>>1;
	build(u<<1,l,mid);
	build(u<<1|1,mid+1,r);
	pushup(u); 
}
void updata(int x,int y,int z)
{
	if(t[x].l==t[x].r)
	{
		t[x].maxx=y;
		return ;
	}
	int mid=(t[x].l+t[x].r)>>1;
	if(z<=mid)
		updata(x<<1,y,z);
	else
		updata(x<<1|1,y,z);
	pushup(x);
}
node query(int x,int l,int r)
{
	if(t[x].l>=l&&t[x].r<=r)
	{
		return {l,r,t[x].maxx,t[x].cnt};
	}
	node res={l,r,-1,0};
	int mid=(t[x].l+t[x].r)>>1;
	if(l<=mid)
	{
		res=query(x<<1,l,r);
	}
	if(r>mid)
	{
		node p=query(x<<1|1,l,r);
		if(res.maxx==p.maxx)
			res.cnt+=p.cnt;
		else if(res.maxx<p.maxx)
		{
			res=p;
		}
	 } 
	 return res;
}
int n,m;
char s[10];
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		scanf("%d",&w[i]);
	build(1,1,n);
	while(m--)
	{
		scanf("%s",s);
		int x,y;
		scanf("%d%d",&x,&y);
		if(s[0]=='A')
		{
			node ans=query(1,x,y);
			cout<<ans.maxx<<" "<<ans.cnt<<endl;
		}
		else
		{
			updata(1,y,x);
		}
	}
}

C题

模拟水题

#include<iostream>
#include<math.h>
using namespace std;
typedef long long ll;
int main()
{
    ll n;
    cin>>n;
    ll cnt=0;
    cnt=n/4;
    ll sum=cnt*2;
    ll m;
    m=n-sum*2;
    if(m==3)
    {
        cout<<sum+1<<endl;
        return 0;
    }
    ll res=m+sum;
    cout<<res<<endl;
}

D题

素数筛
题目的大意就是找最大公约数,素数之间没有最大公约数
所以找到最多可能的素数然后再加上一个非素数就有了最大公约数
所以最后答案就是素数个数+1

//欧拉素数筛
#include<iostream>
#include<cstdio>
#include<string.h>
#include<algorithm>
#include<math.h>
using namespace std;
const int maxn=1e5+5;
int pri[maxn];
int pd[maxn];
void Pri()
{
    int t;//记数
    memset(pri,0,sizeof(pri));
    memset(pd,0,sizeof(pd));
    pd[0]=pd[1]=0;
    for(int i=2;i<=maxn;i++)
    {
        if(!pd[i])
            pri[++t]=i;
        for(int j=1;j<=t&&i*pri[j]<=maxn;j++)
        {
            pd[i*pri[j]]=1;
            if(i*pri[j]==0)
                break;
        }
    }
}
int main()
{
    int n;
    int sum;
    Pri();
    cin>>n;
    if(n<=3)
        cout<<-1;
    else
    {
        for(int i=1;i<=n;i++)
            if(pd[i]==0)
               sum++;
        cout<<sum+1<<endl;
    }
}

E题

字符串模拟相加的弱化版,没有进位,注意一下为0时候特殊判断一下就行

#include<iostream>
#include<string>
using namespace std;
string addStrings(string num1, string num2)
{
	int a1 = num1.size() - 1;
	int a2 = num2.size() - 1;
	string ret;       //相加后的字符串保存在 ret 里面
	int sum = 0;      //两字符串对应位 相加之后的和
	while (a1 >= 0 || a2 >= 0)
	{
		sum = 0;
		if (a1 >= 0)
		{
			sum += num1[a1] - '0';   // 将字符数字转化为 数字 再相加   ‘5’----->5
		}
		if (a2 >= 0)
		{
			sum += num2[a2] - '0';
		}
		if (sum >= 10)     //对应位相加 再加上进位 如果大于>=10说明要进位  更新step为1
		{
			sum -= 10;     //sum-10的值  是相加后当前位的值
		}
		else
		{
			//step = 0;       //如果没有进位step要更新为0  
		}
		ret.insert(0, 1, sum + '0');
		a1--;
		a2--;
	}
	return ret;
}
int main()
{
	string s1;
	string s2;
    string z;
	cin >> s1 >> s2;
	z=addStrings(s1, s2);
    int n=z.length();
    int flag=0;
    for(int i=0;i<n;i++)
    {
        if(z[i]!='0')
        {
            cout<<z[i];
            flag=1;
        }
        else if(flag==1)
        {
            cout<<z[i];
        }
    }
    if(flag==0)
        cout<<0;
	return 0;
}

F题

贪心,一直选最大的那个就行,剩下最后一个不拿;
所以答案就是,全体的和+最大的数*(n-2);

//贪心
#include<iostream>
#include<math.h>
#include<algorithm>
#include<cstdio>
using namespace std;
typedef long long ll;
const int maxn=2e5+5;
int main()
{
    ll n,a[maxn];
    ll maxx=0;
    ll sum=0,res=0;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        maxx=max(maxx,a[i]);
        sum+=a[i];
    }
    res=sum+maxx*(n-2);
    cout<<res<<endl;
}

G题

模拟
先排序然后比较
没有找到比他大的就往下找
找到的话就两个一起向下

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<math.h>
using namespace std;
const int maxn=2e5+5;
int main()
{
    int n,m;
    int a[maxn],b[maxn];
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
    }
    for(int i=1;i<=m;i++)
    {
        cin>>b[i];
    }
    sort(a+1,a+n+1);
    sort(b+1,b+1+m);
    int s1=1,s2=1;
    int cnt=0;
    while(s1<=n&&s2<=m)
    {
        if(a[s1]>b[s2])
        {
            cnt++;
            s1++;
            s2++;
        }
        else
        {
            s1++;
        }
    }
    cout<<cnt<<endl;
}

H题

优先队列的用法,默认大根堆,降序排列

//优先队列
#include<iostream>
#include<queue>
#include<cstdio>
#include<algorithm>
#include<math.h>
using namespace std;
const int maxn=2e5+5;
int a[maxn];
priority_queue<int> q;
int main()
{
    
    int n,m,k;
    cin>>n>>m>>k;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
    }
    sort(a+1,a+1+n);
    for(int i=1;i<=min(k,n);i++)
    {
        q.push(a[i]);
    }
    int c,s;
    for(int i=1;i<=m;i++)
    {
        cin>>c;
        if(c==2)
        {
            if(q.size()<k)
            {
                cout<<-1<<endl;
                continue;
            }
            s=q.top();
            cout<<s<<endl;
        }
        else
        {
            int s;
            cin>>s;
            if(q.size()<k)
            {
                q.push(s);
                continue;
            }
            if(q.top()>s)
            {
                q.pop();
                q.push(s);
            }
        }
    }  
}

I题

J题

dp,从第一个开始向右遍历 dp[i][1]是选第i个,dp[i][0]是不选

#include<iostream>
#include<algorithm>
#include<math.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+5;
ll a[maxn],cnt[maxn],dp[maxn][2];
int main()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        cnt[a[i]]+=a[i];		//题目中说有相同的可以一直拿
    }
    dp[1][1]=cnt[1];
    ll maxx=dp[1][1];
    for(int i=2;i<maxn;i++)		//用桶排序
    {
        dp[i][1]=max(dp[i-1][1],dp[i-1][0]+cnt[i]);//选dp[i-1][1]的话就不能选dp[i];
        dp[i][0]=max(dp[i-1][0],dp[i-1][1]);	   //dp[i][0]不选,就判断dp[i-1]选和不选的情况
        maxx=max(maxx,dp[i][0]);
        maxx=max(maxx,dp[i][1]);
    }
    cout<<maxx<<endl;
}
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值