1. 程式人生 > 其它 >(5/6) Educational Codeforces Round 100 (Div. 2)

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

技術標籤:codeforces演算法

(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

待補