2021-03-05 Educational Codeforces Round 105 (Rated for Div. 2)

A. Three swimmers

A题fist掉了,一个特判没想到,如果x能整除y,那么我一到泳池就能见到他。
如果不是,我到了泳池后,他当前圈已经游了x%y的时间,要见到他还需y-x%y的时间。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

ll cau(ll x, ll y)
{
	if(x % y == 0) return 0;
	else
	{
		x = x % y;
		return y - x;
	}
}

int main()
{
	int t;
	ll p, a[3];
	cin >> t;
	while(t -- ) 
	{
		cin >> p >>a[0] >> a[1] >> a[2];
	    ll minn = cau(p, a[0]);
	    for(int i=1; i<=2; ++ i ) minn = min(minn, cau(p, a[i]));
	    cout << minn << endl;
	}
}

B. Card Deck

因为权值时乘上 n n n^n nn,我们把一摞牌从原数组的尾部拿出来按原先顺序放到新数组的顶部,每次我们拿出以当前值最大的牌为头的一摞牌放到新数组,再从原数组中拿以当前值最大的牌为头的一摞牌,循环。
比赛的时候想到把原数组逆序sort一下,开个结构体同时记录下值和下标,如果执行了取出一摞牌的操作,更新总牌数,用f来记录是否拿过牌,不用考虑第二大值在第一大值的后面,会自动跳过,比赛的时候没有想到记录是否拿过牌,导致牌的总数更新错误,快结束时才A掉。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

struct node{
	int x;
	int idx;
};

bool cmp(node a,node b){
	return a.x > b.x;
}

int main()
{
	int t, n;
	node a[100005];
	int b[100005], p[100005];
	cin >> t;
	while(t -- )
	{
		cin >> n;
		memset(p, 0, sizeof(p));
		memset(a, 0, sizeof(a));
		memset(b, 0, sizeof(b));
		for(int i=0; i<n; ++ i )
		{
			cin >> p[i];
			a[i].x = p[i];
			a[i].idx = i;
		}
		sort(a, a+n, cmp);
		int num = n;
		int k=0;
		int i=0, j;
		bool f=0;
		while(i < n)
		{
			for(j=a[k++].idx; j<num; ++ j)
			{
				b[i ++ ] = p[j];
				f = 1;
			}
			if (f) num = a[k-1].idx;
			f = 0;
		}
		for(int i=0; i<n; i ++ ) cout << b[i] << ' ';
		cout << endl;
	}
}

我们可以从题干中发现牌的值是不重复的,最重要的是只会有n张牌,所以牌的值只会是从1到n的元素都出现一遍(题目的隐含条件真的很重要,以后一定要结合样例多想想)。所以我们只要开个桶存一下权值的下标就行了。
这里给ed赋初值为n + 1是为了减少特判。

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

typedef long long ll;
const int N = 100010;

int p[N], vis[N];
int t, n;

int main()
{
	scanf("%d", &t);
	while (t -- )
	{
		scanf("%d", &n);
		memset(p, 0, sizeof(p)), memset(vis, 0, sizeof(vis));
		for (int i = 1; i <= n; i ++ )
		{
			scanf("%lld", &p[i]); 
			vis[p[i]] = i;
		 } 
		 int ed = n + 1;
		 for (int i = n; i>=1; i -- )
		 {
		 	for (int j = vis[i]; j <= ed - 1; j ++ )
		 	{
		 		printf("%d ", p[j]);
			 }
			 ed = min(ed, vis[i]);
		 }
		 puts("");
	}
	return 0;
 } 

C. Maximum width

有两个字符串找到一个字串,使它下标之差的最大值在所有找到的子序列中是最大的。很明显,我们用双指针分别正向,反向扫描字符串s,记录下t中的字符第一次和最后一次在s中出现的位置,相邻的减一下就是当前部分的最优解,最后再取最大值即可。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 200010;
int n, m;
string s, t;

int main()
{
	cin >> n >> m >> s >> t;
	int lef[N], rig[N];	
	for (int i = 0, j = 0; i < n; i ++ )
	{
		if (t[j] == s[i]) lef[j ++ ] = i;
		if (j >= m) break;
	}
	for (int i = n - 1, j = m - 1; i >= 0; i -- )
	{
		if (t[j] == s[i]) rig[j -- ] = i;
		if (j < 0) break;
	}
	int maxx = 0;
	for (int i = 0; i < m - 1; i ++ )
	{
		maxx = max(maxx, rig[i + 1] - lef[i]);
	}
	printf("%d\n", maxx);
}

D. Genius’s Gambit

呜呜,看题解都想了一个下午,弱弱
首先我们要判断x - y得到的z能否满足有k个1。
已知x和y拥有的0,1数量相等我们知道01这种形式加上1后个数不会发生改变。因此我们可以将y设成10…01…1的形式假设y为1000111。
1.z = 100, x = 1001011 k = 1 2.z = 1100,x = 1010011 k = 2 3.z = 11100,x = 1100011 k = 3 此时我们把这个1移到了最最左端。
4.z = 11110, x = 1100101, k = 4 5.z = 11111, x = 1100110,k = 5
观察可以发现 max(k) = a + b - 2,所以要满足k <= a + b - 2.a = 0或 b = 1的情况需要特判,此时k只能为0。

#include <bits/stdc++.h>
using namespace std;
int a, b, k;
const int N = 200020;
int x[N], y[N], z[N];

int main()
{
	cin >> a >> b >> k;
    if (a == 0 || b == 1)
	{
		if (k) 
		{
			cout << "No" << endl;
			return 0;
		}
		else cout << "Yes" << endl;	
	}	
	else if (a + b - 2 >= k) cout << "Yes" << endl;
	else 
	{
		cout << "No" << endl;
		return 0;
	}
	
	memset(z, 0, sizeof(z));
	x[a + b] = 1, y[a + b] = 1;
	// 构造y 
	for (int i = 1; i < a + b; i ++ )
	{
		if (i <= b - 1) y[i] = 1;
		else y[i] = 0;
		x[i] = y[i];
	}
	
	//构造z
	int st = b - 1, ed = a + b - 2; 
	for (int i = st; i <= ed && k; i ++, k -- ) z[i] = 1;
	ed = b - 2;
	while (k -- )
	{
		z[ed -- ] = 1; 
	}

	// 构造x
	for (int i = 1; i <= a + b; i ++ )
	 {
	 	x[i] += z[i];
	 	if (x[i] >= 2)
	 	{
	 		x[i + 1] += x[i] / 2;
	 		x[i] %= 2;
		 }
	 }
	 
	 // 输出
    for (int i = a + b; i >= 1; i -- ) cout << x[i];
	printf("\n");
	for (int i = a + b; i >= 1; i -- ) cout << y[i];
	printf("\n");
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值