Programming

[CF] Round #572 (Div. 2) _ 210521

minigb 2021. 5. 22. 03:19

https://codeforces.com/contest/1189

 

Dashboard - Codeforces Round #572 (Div. 2) - Codeforces

 

codeforces.com

ㅎㅎ

학코금버

(학회 코포스터디 금요일 버추얼)

 

 

A.

0과 1의 개수가 다르면 그대로 출력해주면 되고, 같으면 맨 앞 하나를 자른 문자열을 출력하면 된다.

맨 앞 한 글자와 나머지로 string을 분리하면 각각에서의 0과 1의 개수가 다를테니까!

int main() {
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	int n; cin >> n;
	string s; cin >> s;
	vector<int> count(2);
	for (int i = 0; i < s.length(); i++) {
		count[s[i] - '0']++;
	}
    
	if (count[0] != count[1]) {
		cout << 1 << kEndl;
		cout << s << kEndl;
	}
	else {
		cout << 2 << kEndl;
		cout << s[0] << ' ';
		for (int i = 1; i < s.length(); i++) {
			cout << s[i];
		}
		cout << kEndl;
	}
}

 

 

B.

쓸 데 없이 두 번이나 틀렸다..

풀이를 빨리 생각해낸 게 너무 신난 바람에 별로 확인 안 해보고 제출했다..

앞으로 이러지 말아야지.

일단 수들을 정렬해놓고, 가장 큰 수가 두 번째로 큰 수와 세 번째로 큰 수의 합보다 작은지 확인한다.

만약 그렇지 않다면 문제에서 요구하는 정렬을 만들 수 없다.

만약 이를 만족하면 다른 수에 대해서는 신경 쓸 필요가 없다.

모든 수에 대해 옆에 자신보다 크거나 같은 수와, 자신보다 작거나 같지만 무조건 1 이상인 수가 있기 때문에 양 옆 값의 합이 무조건 자신보다 크다.

그래서 두 번째로 큰 수 -> 가장 큰 수 -> 세 번째로 큰 수를 출력하고, 이미 정렬된 나머지 수들을 출력하면 답이다.

int main() {
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	int n; cin >> n;
	vector<int> arr(n);
	for (int i = 0; i < n; i++) {
		cin >> arr[i];
	}
    
	sort(arr.begin(), arr.end(), greater<>());
	if (!(arr[0] < arr[1] + arr[2])) {
		cout << "NO" << kEndl;
	}
	else {
		cout << "YES" << kEndl;
		cout << arr[1] << ' ' << arr[0] << ' ' << arr[2] << ' ';
		for (int i = 3; i < n; i++) {
			cout << arr[i] << ' ';
		}
		cout << kEndl;
	}
}

 

 

C.

문제를 어렵게 생각했는데 전혀 어려운 문제가 아니다.

문제에서 특정 구간의 수들을 둘씩 짝지어서 더해나가는 걸 특별한 것 마냥 얘기했지만

그냥 결국 구간 내 수들을 모두 더한다는 의미이다.

그리고 합이 10을 넘을 때 candy가 하나씩 추가되는데

이것 또한 다 더한 후에 확인해도 전혀 문제되지 않는다.

그래서 prefix sum을 이용해서 구간에서의 합을 구하고 10으로 나누는 게 답이다.

int main() {
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	int n; cin >> n;
	vector<int> arr(n + 1);
	for (int i = 1; i <= n; i++) {
		cin >> arr[i];
		arr[i] += arr[i - 1];
	}
	
	int q; cin >> q;
	while (q--) {
		int left, right; cin >> left >> right;
		cout << (arr[right] - arr[left - 1]) / 10 << kEndl;
	}
}

 

 

D1.

결국 못 풀었다

엄청 어려운 문제인 줄 알았는데

사실 효규가 빨리 풀어서 구현이 복잡하거나 어려운 문제가 아닐 것 같긴 했지만

이렇게 간단할 줄은 몰랐다

 

degree가 2인 노드가 존재하면 NO인 것이다...

degree가 1인 노드는 leaf node라는 뜻이니까 문제될 게 없고

degree가 3 이상이면 항상 모든 경우가 가능하다.

학회 스터디에서 끝나고 풀이 얘기할 때 이를 증명했는데

간선이 세 개라고 가정하고, 각각은 리프 노드와 연결되어 있으며, 각각의 가중치가 x, y, z라고 할 때

두 간선을 골라서 값을 더하는 과정을 세 쌍에 대해 시행할 수 있다.

이때 더하는 값을 각각 a, b, c라고 하면

a + b = x

b + c = y

c + a = z를 만드는 a, b, c는 항상 존재한다.

(기분 좋아서 그려봤다)

 

이와 다르게 degree가 2인 노드는 a = x, a = y인 a가 항상 존재하는 건 아니므로 불가능하다.

그리고 degree가 3보다 큰 노드에 대해서는 그 노드에 연결된 간선들 중 3개를 골라서 해당 작업을 한다고 생각하면 되므로 모두 가능하다.

 

진짜...신기했다

효규야 수학과 가라

int main() {
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	int n; cin >> n;
	vector<int> degree(n + 1);
	for (int i = 0; i < n - 1; i++) {
		int u, v; cin >> u >> v;
		degree[u]++;
		degree[v]++;
	}

	bool ans = true;
	for (int i = 1; i <= n; i++) {
		if (degree[i] == 2) {
			ans = false;
			break;
		}
	}

	cout << (ans ? "YES" : "NO") << kEndl;
}

D2는 '간선에 더하는 값이 오직 정수일때 가능한가?'가 문제인데

위에서 말한 것처럼 degree가 3인 노드에 대해서 a, b, c를 구할 때부터 정수가 아닐 수 있고

degree가 3보다 큰 경우는 그 중 세 개의 간선을 골라서 위 작업을 한다고 생각해본다면

매우매우 복잡한 문제가 된다.

 

 

E.

끝나고 풀이 공유할 때 gumgood님께서 풀이해주셨다

이를 만족하는 쌍의 개수를 구하는 문제인데

이렇게 양 변에 두 값의 차를 곱하고 정리하면

결국 

의 값이 같은 쌍의 개수를 구하는 문제가 된다..

 

엄청나다....!!!

ll nC2(int n) {
	return n * (n - 1) / 2;
}

int main() {
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	int n, p, k; cin >> n >> p >> k;
	vector<ll> arr(n);
	for (int i = 0; i < n; i++) {
		cin >> arr[i];
	}

	map<ll, int> cnt;
	for (int i = 0; i < n; i++) {
		ll result = 1;
		for (int j = 0; j < 4; j++) {
			result *= arr[i];
			result %= p;
		}
		result = (result - (arr[i] * k) % p + p) % p;
		cnt[result]++;
	}

	ll answer = 0;
	for (auto iter = cnt.begin(); iter != cnt.end(); iter++) {
		answer += nC2(iter->second);
	}

	cout << answer << kEndl;
}