티스토리 뷰

카테고리 없음

Atcoder Beginner Contest 226

jjang36524 2021. 11. 9. 21:30

총 6문제를 풀면서 5번 틀렸다 ㅠㅠ

A번에서도 틀리는 걸 보면 정확성이 너무 떨어진 것 같다.

A번: 수에 0.5를 더한 뒤 내림하면 반올림이 되는데, 실수 오차를 막기 위해 0.5001을 더했다.

#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
	double N;
	cin >> N;
	cout << (int)(N+0.5001);
}

B번:해싱을 이용해서 배열을 비교한 뒤 풀었는데, 그냥 배열을 set에 넣어도 된다 한다.

#include <iostream>
#include <algorithm>
#include <vector>
#include <set>
#define int long long
using namespace std;
set<int>x;
signed main()
{
	int N;
	cin >> N;
	int i;
	for (i = 0; i < N; i++)
	{
		int K;
		cin >> K;
		int t = 0;
		while (K--)
		{
			int a;
			cin >> a;
			t *= 79;
			t += a+1;
			t %= 7979797979797979LL;
		}
		x.insert(t);
	}
	cout << x.size();
}

C번: 기본적인 dp 문제이다. i번을 배우는 시간은 max(전 기술들을 배우는 시간)+i를 배우는 시간으로 계산할 수 있다.

#include <iostream>
#include <algorithm>
#include <vector>
#include <set>
#define int long long
using namespace std;
int dp[200100];
int r[200100];
int arr[200100][2];
vector<int>l[200100];
signed main()
{
	int N;
	cin >> N;
	int i;
	for (i = 0; i < N; i++)
	{
		int a,b;
		cin >> a>>b;
		arr[i][0] = a;
		arr[i][1] = b; 
		while (b--)
		{
			int x;
			cin >> x;
			l[i].push_back(x);
		}
	}
	r[N-1] = 1;
	int ans = 0;
	for (i = N - 1; i >= 0; i--)
	{
		if(r[i])
			ans += arr[i][0];
		int a = arr[i][1];
		while (a--)
		{
			int x = l[i].back();
			l[i].pop_back();
			if (r[i])
				r[x - 1] = 1;
		}
	}
	cout << ans;
}

D번: x,y의 절댓값이 서로소이면 한 번에 움직여야 하고, 아니면 x,y가 서로소가 되도록 최대공약수로 나눠줄 수 있다. 거기에다가 움직이는 방향의 부호까지 넣어 준 뒤, set을 이용해 서로 다른 움직임의 개수를 관리하면 된다.

#include <iostream>
#include <algorithm>
#include <vector>
#include <math.h>
#include <stdlib.h>
#include <set>
#define int long long
using namespace std;
set<pair<int, int>>xy;
int arr[501][2];
int gcd(int x, int y)
{
	return y ? gcd(y, x % y) : x;
}
signed main()
{
	int N;
	cin >> N;
	int i;
	for (i = 0; i < N; i++)
	{
		cin >> arr[i][0] >> arr[i][1];
		int j;
		for (j = 0; j < i; j++)
		{
			int x = arr[i][0] - arr[j][0];
			int y = arr[i][1] - arr[j][1];
			int xs = x < 0;
			int ys = y < 0;
			x = abs(x);
			y = abs(y);
			int g = gcd(x, y);
			x /= g;
			y /= g;
			xy.insert({ x * (xs ? -1 : 1),y * (ys ? -1 : 1) });
			xy.insert({ x * (xs ? 1 : -1),y * (ys ? 1 : -1) });
		}
	}
	cout << xy.size();
	
}

E번: 각 연결된 component에서 간선 개수와 정점 개수가 다르면 정답은 자명히 0이다. 아니라면 component는 사이클에 트리가 붙어있는 형태일 것이고, 사이클을 시계 방향으로 도는 것과 시계 반대 방향으로 도는 것 2가지 경우가 있을 것이다. 따라서 정답은 2^component 개수가 된다.

#include <iostream>
#include <algorithm>
#include <vector>
#include <math.h>
#include <stdlib.h>
#include <set>
#define int long long
using namespace std;
int uf[200100];
int succ[200100];
int f(int n)
{
	return uf[n] == n ? n : uf[n] = f(uf[n]);
}
int u(int n, int m)
{
	n = f(n);
	m = f(m);
	if (n == m)
	{
		succ[n] = 1;
		return 0;
	}
	succ[m] |= succ[n];
	uf[n] = uf[m];
	return 1;
}
signed main()
{
	int N, M;
	cin >> N >> M;
	if (N != M)
	{
		cout << 0;
		return 0;
	}
	int i;
	for (i = 0; i < N; i++)
	{
		uf[i+1] = i+1;
	}
	int ans = N;
	for (i = 0; i < M; i++)
	{
		int a, b;
		cin >> a >> b;
		ans -= u(a, b);
	}
	for (i = 0; i < N; i++)
	{
		if (!succ[f(i + 1)])
		{
			cout << 0;
			return 0;
		}
	}
	int rans = 1;
	for (i = 0; i < ans; i++)
	{
		rans *= 2;
		rans %= 998244353;
	}
	cout << rans;
}

F번: dp[N][M]을 N명을 사용해서 S(P)가 M이 되도록 하는 경우의 수라고 하자. 여기서 가능한 M은 1000개 정도이고, 전이는 dp[N][M]에서 가능한 모든 크기를 해보면서 그룹을 뽑는 경우*순서를 정하는 경우를 계산한 뒤에 하면 된다. 중복 카운팅을 방지하는 방법은 그룹을 뽑을 때 무조건 가장 왼쪽 원소가 들어가게 뽑는 것이다.

#include <iostream>
#include <algorithm>
#include <vector>
#include <math.h>
#include <stdlib.h>
#include <set>
#define int long long
using namespace std;
int dp[51][100000];
#define MOD 998244353
int mul(int n, int k)
{
	if (k == 0)
		return 1;
	else if (k % 2)
	{
		return n * mul(n, k - 1) % MOD;
	}
	int a = mul(n, k / 2);
	return a * a % MOD;
}
int gcd(int x, int y)
{
	return y ? gcd(y, x % y) : x;
}
int check[1000010];
int revcheck[100100];
int perm[60][60];
signed main()
{
	int N, K;
	cin >> N >> K;
	int i;
	int M=0;
	for (i = 1; i <=180180; i++)
	{
		int su = 0;
		int j;
		int cu = i;
		for (j = 2; j * j <= i; j++)
		{
			int t = 1;
			while (cu % j == 0)
			{
				t *= j;
				cu /= j;
			}
			if (t > 1)
				su += t;
			if (su > N)
				break;
		}
		if (cu>1)
			su += cu;
		if (su <= N)
		{
			M++;
			revcheck[M] = i;
			check[i] = M;
		}
	}
	for (i = 0; i <= N; i++)
	{
		perm[i][0] = 1;
		int j;
		for (j = 1; j <= i; j++)
		{
			perm[i][j] = perm[i][j - 1] * (i - j + 1) % MOD;
		}
	}
	dp[0][1] = 1;
	for (i = 0; i < N; i++)
	{
		int j;
		for (j = 1; j + i <= N; j++)
		{
			int mu = perm[N - i - 1][j - 1];
			int k;
			for (k = 1; k <= M; k++)
			{
				int cu = revcheck[k];
				cu = cu * j / gcd(cu, j);
				if (cu <= 1000000 && check[cu])
				{
					dp[i + j][check[cu]] += dp[i][k]*mu;
					dp[i + j][check[cu]] %= MOD;
				}
			}
		}
	}
	int ans = 0;
	for (i = 1; i <= M; i++)
	{
		int r = mul(revcheck[i], K);
		ans += r * dp[N][i];
		ans %= MOD;
	}
	cout << ans;
}
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
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
글 보관함