(5/6) Educational Codeforces Round 100 (Div. 2)

(5/6) Educational Codeforces Round 100 (Div. 2)

A. Dungeon

题意:

三个数a,b,c代表三个怪物的血量,有一门炮,每次发射会对一个怪物造成伤害1,当发射的次数为7的倍数时,会对三个怪物同时造成1的伤害,要求是否可以在最后一次发射时同时杀死三个怪物。

思路:

求和如果不能被9整除,则输出no。
每一轮会对和减9,最少对每只怪物造成伤害1,所以记录9的次数t,如果存在怪物的初始值小于t,那么输出no。
否则输出yes。

代码:

#include <bits/stdc++.h>
using namespace std;
 
void work() {
	int a, b, c;
	cin >> a >> b >> c;
	int sum = a + b + c;
	int cnt = 0, flag = false;

	cnt = sum / 9, sum %= 9;
	if (sum == 0) flag = true;
	if (!flag) puts("NO");
	else {
		if (a < cnt || b < cnt || c < cnt)  puts("NO");
		else puts("YES");
	}
}
 
int main() {
	int t;
	cin >> t;
	while (t--) work();
}

B. Find The Array

题意:

给定一个数组A,要求构造一个数组B,数组B满足:
相邻的两个元素i,j:要求i被j整除或者j被i整除。
元素的值在1——1e9之间。
A与B数组每个对应元素的差的绝对值之和小于A数组元素之和除以2。

思路:

对于A中的每个元素i:枚举2的x次方,找到其第一次大于i时对应的x,B中对应位置存放2的x-1次方。
证明:
相邻两个数都为2的次方,可以互相整除。
2的x次方大于i,则2的x-1次方小于i,因此数组B中每个元素都小于等于数组A中对应元素的值,因此数组B中元素的值都在1到1e9之间。
2的x次方大于i,2的x-1次方大于i/2,因此B元素对应的值大于i/2,因此其与A对应元素的绝对值只差小于i/2。

代码:

#include <bits/stdc++.h>
#define int long long
using namespace std;
using pii = pair<int, int>;
long long sum = 0;
int a[60];
int b[60];

void work() {
	int n;
	cin >> n;
	for (int i = 0; i < n; i++) {
		cin >> a[i];
		b[i] = a[i];
	}
	for (int i = 0; i < n; i++) {
		int w = 1;
		for (int j = 0; j < 32; j++) {
			if ((w << j) > a[i]) {
				a[i] = (w << (j - 1));
				break;
			}
		}
	}
	for (int i = 0; i < n; i++) cout << a[i] << " "; cout << endl;
}

int32_t main() {
	int t;
	cin >> t;
	while (t--) work();
}

C. Busy Robot

题意:

给出一个数n,代表有n条命令,初始位置在0号点。
每条命令有两个值x,y,x代表时间,y代表目标。
初始时机器人接到命令立刻向目标点出发,在下个命令前如果到达目标点,则到达之后且在下个命令的时间前静止;如果在下个命令发布时,未达到目标点,则会忽略下一个命令,如此类推。
如果机器人在命令i和命令i+1之间经过了i命令的目标点,则i为有效命令,求有效命令的个数。

思路:

模拟,结尾设一个标兵。

代码:

#include <bits/stdc++.h>
#define int long long
using namespace std;
using pii = pair<int, int>;
#define x first
#define y second
constexpr int maxn = 100010;
pii a[maxn];

void work() {
	int n;
	cin >> n;
	for (int i = 1; i <= n; i++) cin >> a[i].x >> a[i].y;
	a[++n] = {10e9, 100e9};
	
	int ans = 0, pos = 1e9 + 10;
	int l = 0, r = 0;
	for (int i = 1; i + 1 <= n; i++) {
		if (pos == 1e9 + 10) pos = a[i].y;
		//cout << pos << "!!" << endl;
		int time = a[i + 1].x - a[i].x;
		int dis = time;
		//cout << i << " " << dis << endl;
		if (pos <= l) {
			r = l - dis;
			if (r <= pos) r = pos, pos = 1e9 + 10;
			if (a[i].y >= min(l,r) && a[i].y <= max(l,r)) ans++;
			l = r;
		} else {
			//cout << "!" << endl;
			r = l + dis;
			if (r >= pos) r = pos, pos = 1e9 + 10;
			if (a[i].y >= min(l,r) && a[i].y <= max(l,r)) ans++;
			l = r;
		}
		//cout << "-------" << l << endl;
		//cout << ans << endl;
	}
	//if (pos == 1e9 + 10) ans++;
	cout << ans << endl;
}

int32_t main() {
	int t;
	cin >> t;
	while (t--) work();
}

D. Pairs

题意:

在一个1-2n的排列当中,我们可以把每两个组成一对,x对取最小值加入A中,n-x对取最大值加入A中。
现在给出A数组,问在1-2n的排列中,我们可以任意组合,一共可以选出几种x,使得其能组成数组A。

思路:

我们把在数组A中的值从小到大加入a中,未在数组A中的值从小到大加入数组b中。
我们确定x的取值范围l,r,那么r-l+1即为所求。
我们二分取x的最大值,也就是最多可以取多少个最小,二分的check函数为a中的前mid个元素是否比b中的后mid个元素小。
我们二分取y的最大值,也就是最多可以取多少个最大,二分的check函数为a中的后mid个元素是否比b中的前mid个元素大。y最大即为x最小,因此x的最小为n-y。
即答案为x-(n-y)+1。

代码:

#include <bits/stdc++.h>
using namespace std;
constexpr int maxn = 1e6;
bool st[maxn];

void work() {
	int n;
	cin >> n;
	memset(st, 0, sizeof st);
	for (int i = 1; i <= n; i++) {
		int x;
		cin >> x;
		st[x] = 1;
	}
	
	vector<int> a, b;
	for (int i = 1; i <= 2 * n; i++) 
		if (st[i]) a.push_back(i);
		else b.push_back(i);
		
	int l = 0, r = n, R, L;
	while (l < r) {
		int mid = l + r + 1 >> 1;
		bool ok = 1;
		for (int i = 0; i < mid; i++) if (a[i] > b[n - mid + i]) ok = 0;
		if (ok) l = mid;
		else r = mid - 1;
	}
	R = l;
	// cout << "---" << R << endl;
	l = 0, r = n;
	while (l < r) {
		int mid = l + r + 1>> 1;
		bool ok = 1;
		for (int i = 0; i < mid; i++) if (b[i] > a[n - mid + i]) ok = 0;
		if (ok) l = mid;
		else r = mid - 1;
	}
	// cout << "!!!" << l << endl;
	cout << R - (n - l) + 1 << endl;
}

int main() {	
	int cas;
	cin >> cas;
	while (cas--) work();
}

E. Plan of Lectures

题意:

做一次演讲,其中一些话题必须在一些话题之前演讲,并且有若干对话题x和y,在x演讲完之后必须紧接着演讲y,问演讲的顺序,不存在输出0,其中每对中的x与其他对的x不同,y也如此。

思路:

我们根据若干对的组合把所有点缩点,由于其一定为一条链或者单个的点,记录链中点的顺序,如果存在环则输出0跳出。
紧接着建图连边,如果两个点属于同一缩点的集合,检查顺序是否符合链的顺序,如果不在同一集合,则连边,再拓扑排序判环,存在环则输出0跳出。
接下来对拓扑排序的缩点集合依次输出每个点集的序列。

代码:

#include <bits/stdc++.h>
using namespace std;
int n, m;
constexpr int maxn = 300010;
int fa[maxn];
int ne[maxn];
int ind[maxn];
int order[maxn];
int cc;
int be[maxn];
vector<int> g[maxn];
vector<int> v[maxn];

void ex() {
	cout << 0 << endl;
	exit(0);
}

void topsort1() {
	// for (int i = 1; i <= n; i++) cout << ind[i] << endl;
	for (int i = 1; i <= n; i++) {
		int tt = 0;
		// cout << "!!!!" << ind[i] << " " << order[i]
		if (!ind[i] && !order[i]) {
			cc++;
			
			// cout << i << endl;
			for (int j = i; j; j = ne[j]) {
				// cout << "---" << endl;
				// cout << j << endl;
				order[j] = ++tt;
				be[j] = cc;
				v[cc].push_back(j);
				if (ne[j] == 0) break;
				ind[ne[j]]--;
			}
			///for (int i = 1; i <= n; i++) cout << order[i] << endl;
			//cout << "---" << endl;
			///for (int i = 1; i <= n; i++) cout << ind[i] << endl;
		}
	}
	for (int i = 1; i <= n; i++)
		if (ind[i]) ex();
		
	// for (int i = 1; i <= n; i++) cout << be[i] << endl;
		
	// cout << "-------" << endl;
	// cout << cc << endl;
}

void topsort2() {
	for (int i = 1; i <= n; i++)  {
		// cout << be[i] << endl;
		if (fa[i]) {
			if (be[i] == be[fa[i]]) {
				// cout << "!!" << endl;
				if (order[fa[i]] > order[i]) ex();
			} else {
				g[be[fa[i]]].push_back(be[i]);
				// cout << "---" << be[fa[i]] << endl;
				ind[be[i]]++;
			}
		} 
	}
	
		
		
	// cout << "-------" << endl;
	
	queue<int> q;
	for (int i = 1; i <= cc; i++)
		if (ind[i] == 0) q.push(i);
	//cout << "---" << q.front() << endl;
	//cout << g[q.front()][0] << endl;
	//cout << g[q.front()][1] << endl;
	//cout << g[2].size() << endl;
	vector<int> res;
	while (q.size()) {
		//cout << "!!!!!!!!!!!!!" << endl;
		int u = q.front();
		//cout << "---" << u << endl;
		q.pop();
		//cout << q.size() << endl;
		res.push_back(u);
		for (int i = 0; i < g[u].size(); i++) {
			//cout << u << " " << "!" << endl;
			//cout << g[u][i] << " " << ind[g[u][i]] << endl;
			if (--ind[g[u][i]] == 0) {
				q.push(g[u][i]);
				//cout << "!!!" << endl;
				//cout << g[u][i] << endl;
			}
			// cout << g[u][i] << endl;
		}
			
	}
	//cout << res.size() << endl;
	// for (int i = 0; i < res.size(); i++) cout << res[i] << endl;
	if (res.size() != cc) ex();
	
	// cout << "-------" << endl;
	
	for (auto i : res)
		for (auto j : v[i])
			cout << j << " "; 
			
	cout << endl;
}

int main() {	
	cin.tie(0);
  	cout.tie(0);
  	ios_base::sync_with_stdio(false);
	cin >> n >> m;
	for (int i = 1; i <= n; i++) cin >> fa[i];
	for (int i = 1; i <= m; i++) {
		int x, y;
		cin >> x >> y;
		ne[x] = y;
		ind[y]++;
	}
	topsort1();
	topsort2();
}

F. Max Correct Set

待补

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值