牛客练习赛41 ABCDE题解

本文精选了五道算法竞赛题目,包括硬币翻转、RPG游戏策略、盗窃犯追捕、最小相似度计算及球体体积并集的求解。通过详细解析,展示了如何运用并查集、动态规划、最短路径等算法解决复杂问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

A.翻硬币问题

签到题,n!=m就No,我简单证明一下,如果n为奇数,每次翻转硬币,正面朝上的贡献都是偶数次,永远也不可能,如果n为偶数,那么我翻转一枚硬币,现有的正面朝上的数量是奇数,但是Alice每次翻转贡献是偶数次,所以也不可能。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int main()
{
	int T,n,m;
	cin>>T;
	while(T--)
	{
		cin>>n>>m;
		if(n==m)puts("Yes");
		else puts("No");
	}
}

B.666RPG

设d[ i ][ j ]为第 i 个回合时,数字变成 j 的方案数,转移很简单,d[ i ][ j ]=d[ i-1 ][ -j ]+d[ i-1 ][ j-a[ i ] ],但是面临着下标为负数的情况,因此把所有数字都加上666*300,即666*300代表数字0,然后就水题了。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=666*2*300+10,mod=1e8+7,N=666*300;
ll d[2][maxn];
int a[305],cur,n;
void add(ll& x,ll y)
{
	x=(x+y)%mod;
}
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)cin>>a[i];d[0][N]=1;
	for(int i=1;i<=n;i++)
	{
		cur=!cur;
		for(int j=0;j<maxn;j++)d[cur][j]=0;
		for(int j=0;j<maxn;j++)
		if(d[!cur][j])
		{
			add(d[cur][j+a[i]],d[!cur][j]);
			add(d[cur][2*N-j],d[!cur][j]);
		}
		d[cur][N+666]=0;
	}
	cout<<d[cur][N-666];
}

C.抓捕盗窃犯

带权并查集 ,用并查集把联通块联通起来并算出联通快的总权值即可。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e5+10;
int to[maxn],p[maxn],vis[maxn],cnt;
ll d[maxn],res[maxn],ans;
int find(int u)
{
	if(p[u]!=u)
	p[u]=find(p[u]);
	return p[u];
}
int main()
{
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)scanf("%lld",&d[i]),p[i]=i;
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&to[i]);
		int fa=find(i),fb=find(to[i]);
		if(fa!=fb)
		{
			p[fa]=fb;
			d[fb]+=d[fa];
		}
	}
	for(int i=1;i<=n;i++)
	{
		int fa=find(i);
		if(!vis[fa])
		{
			res[++cnt]=d[fa];
			vis[fa]=1;
		}
	}
	sort(res+1,res+1+cnt);
	for(int i=cnt;i;i--)
	{
		ans+=res[i];
		if(cnt-i+1==m)break;
	}
	printf("%lld\n",ans);
}

D.最小相似度

这个题很多人用fwt,我不会,看到有大佬用最短路过了这个题,真是学到了 orz

思路:设d[ i ]为状态初始的 n 个状态 异或 i 后,所能得到最少的1的个数,那么设初始的 n 个状态的d[ s ]=0,然后进队,跑最短路即可。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=2e6+10;
int d[maxn],ans=20,n,m;
char s[30];
queue<int>q;
int main()
{
	cin>>n>>m;
	for(int i=0;i<(1<<m);i++)d[i]=m;
	for(int i=1;i<=n;i++)
	{
		scanf("%s",s);
		int x=0; 
		for(int j=0;j<m;j++)
		if(s[j]=='1')x|=(1<<j);
		d[x]=0;
		q.push(x);
	}
	while(!q.empty())
	{
		int u=q.front();q.pop();
		for(int j=0;j<m;j++)
		{
			int v=(u^(1<<j));
			if(d[v]>d[u]+1)
			{
				d[v]=d[u]+1;
				q.push(v);
			}
		}
	}
	for(int i=0;i<(1<<m);i++)
	ans=min(ans,m-d[i]);
	cout<<ans;
}

E.球的体积并

ccpc camp有一个题是求球题的体积交,把那个题的解法稍微改改就行,不贴代码了,

ccpc camp:CCPC-Wannafly Winter Camp Day2 H.Cosmic Cleaner

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

长沙橘子猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值