티스토리 뷰

카테고리 없음

ABC 209

jjang36524 2021. 7. 10. 22:52

ABC 209를 봤고, 5문제를 풀었다.

A번: 단순한 계산 문제이다. A>B인 경우를 생각 안 해서 한 번 틀렸다.

#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
#include <queue>
using namespace std;
vector<int>link[200100];
int arr[200100];
int d[200100];
int p[200100][20];
int main()
{
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	int T,N, M, a, b, c;
	cin >> N >> M;
	vector<int>x;
	int i;
	cout << max(0,M - N + 1);
}

B번: 전체 물건의 가격은 기본 가격의 합-N/2이다. X가 이보다 큰지 작은지 판별하면 된다.

#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
#include <queue>
using namespace std;
int main()
{
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	int T,N, M, a, b, c;
	cin >> N >> M;
	vector<int>x;
	int i;
 
	for (i = 0; i < N; i++)
	{
		int a;
		cin >> a;
		M -= a - i % 2;
	}
	cout << (M < 0 ? "No" : "Yes");
}

C번: 조합론 문제이다. 우선 C를 오름차순으로 정렬해준다. i번째가 가질 수 있는 경우의 수는 Ci-i+1개이다. 왜냐하면 1~Ci가 가능한데, 1번째에서 i-1번째까지는 쓸 수 없기 때문이다.

#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
#include <queue>
#define int long long
using namespace std;
signed main()
{
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	int T, N, M, a, b, c;
	cin >> N;
	vector<int>x;
	int i;
	for (i = 0; i < N; i++)
	{
		int a;
		cin >> a;
		x.push_back(a);
	}
	sort(x.begin(), x.end());
	int ans = 1;
	for (i = 0; i < N; i++)
	{
		ans *= max(0LL, x[i] - i);
		ans %= 1000000007;
	}
	cout << ans;
 }

D번: 퍼솔을 노리기 위해 가장 먼저 푼 문제이다. 두 사람이 움직이는 거리는 트리에서의 거리와 같고, 이 거리가 홀수면 중간에서 만나고, 짝수면 마을에서 만난다. 거리는 lca를 통해 구할 수 있다. 퍼솔은 실패하고 5번째로 풀었다.

#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
#include <queue>
using namespace std;
vector<int>link[200100];
int arr[200100];
int d[200100];
int p[200100][20];
void pp(int n, int de)
{
	d[n] = de;
	int i;
	for (i = 1; i < 20; i++)
	{
		p[n][i] = p[p[n][i - 1]][i - 1];
	}
	for (i = 0; i < link[n].size(); i++)
	{
		if (!d[link[n][i]])
		{
			p[link[n][i]][0] = n;
			pp(link[n][i], de + 1);
		}
 
	}
}
int lca(int a, int b)
{
	if (d[a] < d[b])
		swap(a, b);
	int di = d[a] - d[b];
	int i;
	for (i = 19; i >= 0; i--)
	{
		if ((1 << i) & di)
			a = p[a][i];
	}
	if (a == b)
		return a;
	for (i = 19; i >= 0; i--)
	{
		if (p[a][i] != p[b][i])
		{
			a = p[a][i];
			b = p[b][i];
		}
	}
	return p[a][0];
}
int main()
{
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	int T,N, M, a, b, c, i;
	cin >> N >> M;
	for (i = 1; i < N; i++)
	{
		int a, b;
		cin >> a >> b;
		link[a].push_back(b);
		link[b].push_back(a);
	}
	pp(1, 1);
	while (M--)
	{
		int a, b;
		cin >> a >> b;
		int r = d[a] + d[b] - 2 * d[lca(a, b)];
		cout << (r % 2 ? "Road":"Town")<<'\n';
	}
}

E번: 문자열을 그대로 다루기는 힘들어 보이니, 첫 3글자의 조합과 마지막 3글자의 조합을 수로 나타내자. 이러면 단어 하나는 3글자 조합에서 다른 3글자 조합으로 가는 간선이 되고, 게임은 이 그래프에서 이루어지게 된다. 결과를 예측하기 위해, 특정 단어로 이어나가야 할 때, 지는지 이기는지를 알아야 한다. 지는 경우는 이어나갈 수 없거나, 이어나가는 모든 경로가 이기는 경우로 이어지는 2가지다. 이기는 경우는 지는 경우로 이어나갈 수 있는 경우 1가지다. 나머지 경우는 모두 비기는 경로이다. 이를 구하기 위해 뒤집힌 간선들로 이루어진 그래프에서 변형된 위상 정렬을 사용한다. 처리될 조건은 지는 경우임이 확실하거나, 이기는 경우임이 확실한 경우 2가지로, 이 경우들이 나오면 상태를 저장하고 간선 뒤에 있는 노드들을 처리한다. case work 때문에 3틀 후 ac

#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <string>
#define int long long
using namespace std;
vector<int>link[200000];
int lc(char x)
{
	if (x <= 'Z')
		return x - 'A'+26;
	else
		return x - 'a';
}
int stp[200100];
int enp[200100];
int pos[200100];
int cou[200100];
int vis[200100];
signed main()
{
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	int T = 52 * 52 * 52;
	int N;
	cin >> N;
	int i;
	for (i = 0; i < N; i++)
	{
		string s;
		cin >> s;
		int j;
		int r = 0;
		int c = 1;
		for (j = 0; j < 3; j++)
		{
			r += c * lc(s[j]);
			c *= 52;
		}
		stp[i] = r;
		r = 0;
		c = 1;
		for (j = 0; j < 3; j++)
		{
			r += c * lc(s[j+s.size()-3]);
			c *= 52;
		}
		link[r].push_back(stp[i]);
		cou[stp[i]]++;
		enp[i] = r;
	}
	queue<int>tps;
	for (i = 0; i < T; i++)
	{
		if (cou[i] == 0)
			tps.push(i);
	}
	while (tps.size())
	{
		int a = tps.front();
		tps.pop();
		if (pos[a] == 0)
			pos[a] = -1;
		for (i = 0; i < link[a].size(); i++)
		{
			if (pos[a] == -1)
				pos[link[a][i]] = 1;
			cou[link[a][i]]--;
			if ((cou[link[a][i]] == 0 || pos[link[a][i]] == 1) && !vis[link[a][i]])
			{
				vis[link[a][i]] = 1;
				tps.push(link[a][i]);
			}
				
		}
	}


	for (i = 0; i < N; i++)
	{
		if (pos[enp[i]] == 1)
			cout << "Aoki";
		else if (pos[enp[i]] == -1)
			cout << "Takahashi";
		else
			cout << "Draw";
		cout << '\n';
	}
}

F번: 풀지는 못했지만, 이웃한 원소의 크기가 작을 경우 큰 원소부터 처리해야 한다는 관찰을 하였다.

총평: F번이 그리 어려워 보이지 않았는데 풀지 못해서 아쉽고, E번 같은 문제는 한 번에 풀 수 있도록 노력을 해야겠다는 생각이 들었다.

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함