AtCoder Beginner Contest 360

A - A Healthy Breakfast

枚举一下,只要R在M之前就行了

#include <iostream>

using namespace std;

int main()
{
	char a,b,c;
	cin >> a >> b >> c;
	
	if((a == 'R' && (b == 'M' || c == 'M')) || (b == 'R' && c == 'M'))
	{
		cout << "Yes" << endl;
	}
	else cout << "No" << endl;
	
	return 0;
}

B - Vertical Reading 

题意:把字符串每隔w个字符拆分一次,取每段的第c个字符拼接在一起,看能不能得到t

数据范围很小,直接暴力枚举(*^_^*)

#include <iostream>

using namespace std;

int main()
{
	string a, b;
	cin >> a >> b;
	
	a = ' ' +a;
	
	int na = a.size()-1;
	
	//枚举每一种长度
	for(int w = 1; w < na; w++)
	{
		//枚举c
		for(int c = 1; c <= w; c++)
		{
			string ans = "";
			for(int i = 1; i <= na; i += w)
			{
				//判断第c个字符是否超过字符串长度
				if(i + c - 1 <= na) ans += a[i + c - 1];
			}
			if(ans == b) 
			{
				puts("Yes");
				return 0;
			}
		}
	}
	
	puts("No");
	
	return 0;
}

C - Move It

分析:因为最终每个箱子中只有一个小球,并且要使移动的代价最小,所以只需要把每个箱子里除去最大权值的物品逐个加起来即可,代码如下:

#include <iostream>
#include <algorithm>
#include <vector>
#include <map>

using namespace std;

const int N = 1e5+10;

int w[N];

bool cmp(int i, int j)
{
	return w[i] < w[j];
}

int main()
{
	int n;
	cin >> n;
	
	map<int, vector<int>> mp;
	
	int x;
	for(int i = 1; i <= n; i++) 
	{
		cin >> x;
		mp[x].push_back(i);
	}
	
	for(int i = 1; i <= n; i++) cin >> w[i];
	
	long long ans = 0;
	
	for(auto t : mp)
	{
		vector<int> v = t.second;
		
		if(v.size() <= 1) continue;
		
		sort(v.begin(), v.end(), cmp);
		//把除了最大的数加起来
		for(int i = 0; i < v.size() - 1; i++)
		{
			ans += w[v[i]];
		}
		
	}
	
	cout << ans << endl;
	
	return 0;
}

D - Ghost Ants

分析:因为所有蚂蚁的速度都是相同的,所以方向相同的蚂蚁是不会碰头的,这样就可以把蚂蚁分成两个部分,一部分朝向正方向,一部分朝向负方向,然后我们就可以枚举正方向的每个蚂蚁都能与负方向的哪些蚂蚁碰头,为了降低时间复杂度,这个过程我们可以先将负方向的蚂蚁位置进行从小到大排序,然后利用二分来去寻找合适能碰头的蚂蚁的数量,代码如下:

#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

int main()
{
	int n;
	long long t;
	cin >> n >> t;
	
	string s;
	cin >> s;
	
	s = ' ' + s;
	
	vector<long long> a;
	vector<long long> b;
	
	long long x;
	for(int i = 1; i <= n; i++) 
	{
		cin >> x;
		if(s[i] == '1') a.push_back(x);
		else b.push_back(x);
	}
	
	sort(a.begin(), a.end());
	sort(b.begin(), b.end());
	
	long long ans = 0;
	
	for(long long y : a)
	{
		auto l = lower_bound(b.begin(), b.end(), y), r = upper_bound(b.begin(), b.end(), y + t + t);
		ans += r - l;
	}
	
	cout << ans << endl;
	
	return 0;
}

E - Random Swaps of Balls 

分析:首先对于位置1,黑球有两种选择,一是改变位置,二是保持在原地,然后我们可以计算一次操作黑球的期望位置:

对于保持在原地,我们可以两个都不选择位置1处的球,它的概率是\frac{(n-1)^{2}}{n^{2}},也可以选择两个都是位置1处的球,它的概率为\frac{1}{n^{2}},因此,保持原地的概率为\frac{(n-1)^{2}+1}{n^2},此时保持原地的期望为\frac{(n-1)^{2}+1}{n^2}*1

对于改变位置,我们有\frac{1}{n}的概率选择位置1,有\frac{1}{n}的概率选择其他位置,并且两者可以互换位置,所以要乘以2,那么期望位置为:2*\frac{1}{n}*(\frac{1}{n}*2 + \frac{1}{n}*3+...+\frac{1}{n}*n)=2*\frac{1}{n^{2}}*(2+3+...+n)=2*\frac{1}{n^{2}}*(1+2+3+...+n - 1)=\frac{2}{n^{2}}*(\frac{(n+1)*n}{2} - 1)

将两者相加后即是一次操作后的期望位置。

算出这次的期望位置后,我们通过此次的期望位置来算出后面的期望位置,只是需要把保持在原地乘以1换成乘以此次的期望值,把改变位置的期望值中减1,改成减去此次的期望值,假如此次的期望为f[i],则f[i]=\frac{(n-1)^{2}+1}{n^{2}}*f[i-1]+\frac{2}{n^{2}}*(\frac{n*(n+1)}{2}-f[i-1])

然后循环k次就可以了,

对于第0次,它的期望就是1,代码如下:

#include <iostream>

using namespace std;

using ll = long long;

const int mod = 998244353, N = 1e5+10;

ll f[N];

ll qmi(ll a, ll b)
{
	ll res = 1;
	a%=mod;
	while(b)
	{
		if(b&1) res = 1LL * res * a % mod;
		a = 1LL * a * a % mod;
		b >>= 1;
	}
	return res;
}

ll inv(ll x)
{
	return qmi(x, mod-2);
}

int main()
{
	ll n, k;
	cin >> n >> k;
	
	f[0] = 1;
	
	//求n*n逆元
	ll invn = inv(n*n);
	ll sum = ((n-1) * (n-1) % mod + 1) % mod; 
	ll p = (n + 1)*n / 2 % mod;

	for(int i = 1; i <= k; i++)
	{
		f[i] = f[i-1]*sum % mod * invn % mod;
		f[i] += 2LL * invn % mod * (p - f[i-1]) % mod;
		f[i] = (f[i] % mod + mod)%mod;
	}
	
	cout << f[k] << endl;
	
	return 0;
}

F、E不会,以后再补

  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值