牛客周赛 Round 53(葡萄城杯)小白题解A-E

acwing转战CSDN,发现CSDN写题解更方便

比赛链接

A-小红小紫投硬币(数学推导)

题意

A和B投硬币,有正反两面的结果,概率为0.5,A投了n个硬币,B投了n+1个硬币,求B投的正面次数比A的多的概率

思路

可以证明,无论n等于多少,概率都是0.5,输出即可

代码

#include <iostream>
#include <cstring>
#include <queue>
#include <map>
#include <set>
#include <algorithm>
#include <cmath>
#include <vector>
#include <stack>
using namespace std;
typedef long long LL;
typedef pair<LL,LL> PII;//开long long,求求你了,记得开long long 
const LL N=1e5+10;
const LL INF=1e18;
const double small=1e-16;
//千万不要用puts()和gets(),求求你了 


void solve()
{
	double n;
	cin>>n;
	cout<<"0.5"<<endl;
}

int main()
{
    
	int t=1;
	//cin>>t;
	while(t--)
	{
		solve();
	}
	return 0;
}

B-小红的字符串(字符串)

题意

给定一个由小写字母组成的字符串s,可以进行一种操作:对字符串中一个字符进行右移操作,’z‘右移变为’a‘,求把s变为回文串的最小操作数。

思路

注意看题,只能右移,不能左移(我没看仔细,引以为戒),求出对称的两个字符串变成相同字符串所需要的次数,有两种情况:可以是左边字符右移,可以是右边字符右移,取最小累加即可。

代码

#include <iostream>
#include <cstring>
#include <queue>
#include <map>
#include <set>
#include <algorithm>
#include <cmath>
#include <vector>
#include <stack>
using namespace std;
typedef long long LL;
typedef pair<LL,LL> PII;//开long long,求求你了,记得开long long 
const LL N=1e5+10;
const LL INF=1e18;
const double small=1e-16;
//千万不要用puts()和gets(),求求你了 

int work(char a,char b)
{
    if(a>b)swap(a,b);
    int s=abs(a-b);
    int ss=(a-'a'+'z'-b)+1;
    return min(s,ss);
}

void solve()
{
	string s;
    cin>>s;
    int n=s.size();
    int ans=0;
    for(int i=0;i<n/2;i++)
    {
        if(i>=n/2)continue;
        int tmp=work(s[i],s[n-1-i]);
        ans+=tmp;
    }
    cout<<ans<<endl;
}

int main()
{
    
	int t=1;
	//cin>>t;
	while(t--)
	{
		solve();
	}
	return 0;
}


C-小红的 01 消除(贪心 字符串)

题意

给定一个由0和1组成的字符串,可以进行3种操作:

1.删除11子串

2.删除01子串

3.删除00子串

操作分别有x,y,z的次数限制

求进行操作2的最多次数

思路

x和z没啥用,只需要检测01的个数,遍历整个字符串,有两种读取模式,第一步先读连续的0,再读后面连续的1,两个个数取最小就是01的个数,重复两种模式,直到字符串结束,然后再和y取小值就行。

代码

#include <iostream>
#include <cstring>
#include <queue>
#include <map>
#include <set>
#include <algorithm>
#include <cmath>
#include <vector>
#include <stack>
using namespace std;
typedef long long LL;
typedef pair<LL,LL> PII;//开long long,求求你了,记得开long long 
const LL N=1e5+10;
const LL INF=1e18;
const double small=1e-16;
//千万不要用puts()和gets(),求求你了 


void solve()
{
	int n;
    string s;
    cin>>n>>s;
    int x,y,z;
    cin>>x>>y>>z;
    int wait=0;
    int idx=0;
    int res=0;
    int last0=0,last1=0;
    while(idx<n)
    {
        if(wait==0)
        {
            if(idx<n&&s[idx]=='0')
            {
                while(idx<n&&s[idx]=='0')idx++,last0++;
                wait=1;
            }
            else if(idx<n&&s[idx]=='1')
            {
                idx++;
            }
        }
        else
        {
            if(idx<n&&s[idx]=='1')
            {
                while(idx<n&&s[idx]=='1')idx++,last1++;
                //cout<<last0<<" "<<last1<<endl;
                res+=min(last1,last0);
                last1=0;
                last0=0;
                wait=0;
            }
            else if(idx<n&&s[idx]=='0')
            {
                idx++;
            }
        }
    }
    cout<<min(res,y)<<endl;
}

int main()
{
    
	int t=1;
	//cin>>t;
	while(t--)
	{
		solve();
	}
	return 0;
}

D-小红组比赛(分组DP)

题意

一共有n场比赛,每场比赛有m道题,现在从这些比赛中抽n道题(每场比赛必须抽一道),组成一场比赛,有一个目标难度,求比赛难度(题目难度相加)与目标难度的最小绝对值。

思路

分组dp是看大佬的讲解学会的:背包问题----分组背包(超详细讲解)-CSDN博客

分组dp的板子题,赛时写了一个dfsTLE了;

和01背包类似,但是分组背包把物品分为n个组,每个组最多只能选一个,然后求最大,这道题求的是最小绝对值,所以可以存储在范围中的每个数是否出现过,可以发现,到第n层的出现数字可以由第n-1层的出现数字推出,最后在第n层出现的数字中取最小绝对值就好了。

代码

#include <iostream>
#include <cstring>
#include <queue>
#include <map>
#include <set>
#include <algorithm>
#include <cmath>
#include <vector>
#include <stack>
using namespace std;
typedef long long LL;
typedef pair<LL,LL> PII;//开long long,求求你了,记得开long long 
const LL N=1e5+10;
const LL INF=1e18;
const double small=1e-16;
//千万不要用puts()和gets(),求求你了 
LL num[110][30];
LL ans[N];

void solve()
{
	LL n,m;
	cin>>n>>m;
	LL maxx=0;
	for(int i=1;i<=n;i++)
	{
		LL tmp=0;
		for(int j=1;j<=m;j++)cin>>num[i][j],tmp=max(tmp,num[i][j]);
		ans[i]=tmp;
		maxx+=tmp;
	}
	vector<bool> dp(maxx+1,false);
	LL k;
	cin>>k;
	dp[0]=true;
	for(int i=1;i<=n;i++)
	{
		vector<bool> dp2(maxx+1,false);
		for(int j=1;j<=m;j++)
		{
			for(int k=maxx-num[i][j];k>=0;k--)
			{
				if(dp[k])
				{
					dp2[k+num[i][j]]=true;
				}
			}
		}
		dp=dp2;
	}
	LL ans=INF;
	for(int i=maxx;i>=0;i--)
	{
		if(dp[i])ans=min(ans,abs(i-k));
	}
	cout<<ans<<endl;
}

int main()
{
    
	int t=1;
	//cin>>t;
	while(t--)
	{
		solve();
	}
	return 0;
}

E-折半丢弃(二分 MEX)

题意

给定一个由n个整数构成的数组a,可以对数组进行一种操作,取一个数,进行折半下取整,然后求若干操作后能够取得的最大MEX值(数组中没有出现的最小整数)

思路

我们可以对MEX值进行二分,具有二分的性质,因为当数组可以使得MEX值为a时,也可以使得MEX值为(b<a),所以,我们先对MEX-1进行二分,找到满足条件的最大MEX(右端点),check函数写法:先把所有的大于mid的数折半为小于或等于mid的数,然后再从大到小进行枚举,出现次数大于1的大数可以折半为小数,然后通过贪心构造后判断是否能够实现从0-mid的数字全部出现过。

代码

#include <iostream>
#include <cstring>
#include <queue>
#include <map>
#include <set>
#include <algorithm>
#include <cmath>
#include <vector>
#include <stack>
using namespace std;
typedef long long LL;
typedef pair<LL,LL> PII;//开long long,求求你了,记得开long long 
const LL N=1e5+10;
const LL INF=1e18;
const double small=1e-16;
//千万不要用puts()和gets(),求求你了 
LL a[N];
LL b[N];
LL n;

bool check(LL mid)
{
	map<LL,LL> has; 
	for(int i=1;i<=n;i++)
	{
		b[i]=a[i];
		while(b[i]>mid)
		{
			b[i]/=2;
		}
		has[b[i]]++;
	}
	LL idx=mid;//从大到小进行构造 
	while(idx>=0&&has[idx])
	{
		
		has[idx/2]+=has[idx]-1;//大的留一个,其他全化为小的 
		idx--;
		if(idx<=-1)break;
	}
	return idx==-1;//枚举是否能够使得MEX=mid+1(是否存在0-mid) 
}

void solve()
{
	cin>>n;
	for(int i=1;i<=n;i++)cin>>a[i];
	LL l=0,r=1e9+10;
	while(l<r)
	{
		LL mid=(l+r+1)/2;
		if(check(mid))l=mid;//求右端点,向左延伸,封左 
		else r=mid-1;	
	}	
	cout<<l+1<<endl;
}

int main()
{
    
	int t=1;
	cin>>t;
	while(t--)
	{
		solve();
	}
	return 0;
}

小小菜鸡水平不足,剩下两道题看不懂了,先溜了

F-小红走矩阵

G-游游的删点直径

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值