AtCoder Beginner Contest 402题解

A - CBC

思路:仔细看这题其实就发现,我们只需要遍历一遍字符串把大写字母输出即可,很标准的签到题

#include<bits/stdc++.h>
using namespace std;
#define int long long

signed main()
{
	string s;
	cin>>s;
	for(char c:s)
	{
		if(c>='A'&&c<='Z')
		{
			cout<<c;
		}
	}
	return 0;
}

 B - Restaurant Queue

思路:直接用双端队列deque模拟一遍直接过

 

#include<bits/stdc++.h>
using namespace std;
#define int long long 
deque<int> que;
int q;
int x;
int flag;
signed main()
{
	cin>>q;
	while(q--)
	{
		cin>>flag;
		if(flag==1)
		{
			cin>>x;
			que.push_back(x);
		}
		else
		{
			cout<<que.front()<<"\n";
			que.pop_front();
		}
	}
	return 0;
}

C - Dislike Foods

思路:我们可以用map去存储第i个食材在第几天克服,因此我们可以知道每个菜最早在第几天可以吃,我们将第i天可以吃的食物累加起来,最后跑一遍累加和直接解决问题

#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,m;
vector<int> e[300005];
map<int,int> mp;//每个食材是第几天的 
map<int,int> day;//第几天解锁当前菜品 
signed main()
{
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	{
		int k;
		cin>>k;
		for(int j=1;j<=k;j++)
		{
			int x;
			cin>>x;
			e[i].push_back(x);
		}
	}
	for(int i=1;i<=n;i++)
	{
		int x;
		cin>>x;
		mp[x]=i;
	}
	for(int i=1;i<=m;i++)
	{
		int ans=0;
		for(int j:e[i])
		{
			ans=max(ans,mp[j]);
		}
		day[ans]++;
	} 
	int sum=0;
	for(int i=1;i<=n;i++)
	{
		sum+=day[i];
		cout<<sum<<"\n";
	}
	return 0;
}

D - Line Crossing

思路:我们发现只要不在一条水平线上就肯定会相交,我们考虑一下加入给你n条线段,n条线段都互不平行,那么最后会有多少种这个满足的线对呢?答案是肯定的n*(n-1)/2,那么我们只需要减去平行线段多余的贡献即可

这题的考点在于如何去判断两条直线是平行的,如果我们足够仔细,我们会发现其实线段中其实也就只会出现n种斜率,刚好对应端点数,我们只需要判断其两个端点的和取模n的数即可,我们用cnt数组去存储(a+b)%n即可,然后我们在在总满足线对中,减去同斜率的端点对即可

#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,m;
int cnt[1000005];
signed main()
{
	cin>>n>>m;
	int ans=m*(m-1)/2;
	for(int i=1;i<=m;i++)
	{
		int a,b;
		cin>>a>>b;
		cnt[(a+b)%n]++;
	}
	for(int i=0;i<n;i++)
	{
		ans-=cnt[i]*(cnt[i]-1)/2;
	}
	cout<<ans;
	return 0;
}

 E - Payment Required

思路:一个状压+概率dp的一个问题 

我们看数据n<=8,一眼就看出来需要用状态压缩我们可以考虑当前已经选择的当前的状态用二进制存储即可,然后我们考虑dp的状态是什么,dp[i][j]表示剩下i元,选择的状态为j的最大期望,然后我们只需要在第一层循环去遍历剩下多少钱,第二层循环遍历状态,第三层循环去遍历要加入的点即可

然后我们考虑一下状态转移方程式

当前选择k做对的概率为p[k]

那么当前选择k做错的概率为(1-p[k])

那么我们当前胜利获得的期望为s[k]+dp[i-c[k]][j|(1<<k)]

那么我们当前失败所得期望为dp[i-c[k]][j]

因此我们总的期望=对的概率*对的期望+错的概率*错的期望

我们之间跑即可

最后输出dp[n][0]即可

#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,x;
int s[10];
int c[10];
int p[10];
double dp[5005][1 << 10];
signed main()
{
    cin >> n>>x;
    for (int i = 0; i < n;i++)
    {
        cin >> s[i] >> c[i] >> p[i];
    }
    for (int i = 0; i <=x;i++)
    {
        for (int j = 0; j < (1 << n); j++)
        {
            double ans = 0;
            for (int k = 0; k < n;k++)
            {
                if((j>>k)&1||c[k]>i)
                {
                    continue;
                }
                double pi = p[k] / 100.0;
                double suc = s[k] + dp[i - c[k]][j|(1<<k)];
                double fal = dp[i - c[k]][j];
                ans = max(ans, pi * suc + (1 - pi) * fal);
            }
            dp[i][j] = ans;
        }
    }
    cout << fixed << setprecision(10) << dp[x][0] << endl;
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值