티스토리 뷰

jjang36524 계정으로 가서 5솔을 했다.

A번: x가 interesting할 조건은 x에다가 1을 더할 때 자리올림이 일어나는 것이다. 자리올림이 없을 때는 합에 1이 더해지지만, 매 자리올림마다 9 하나가 0이 됨으로써 합이 작아지기 때문이다. 자리올림이 일어날 조건은 x를 10으로 나눈 나머지가 9일 때고, 이는 [(x+1)/10의 식으로 구할 수 있다.]

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main()
{
	int T;
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	cin >> T;
	while (T--)
	{
		int N;
		cin >> N;
		cout << (N + 1) / 10 << '\n';
	}
}

B번: 나올 가능성이 있는 문자열은 정수 i,j,k(i<=j>=k)로 정의될 수 있는데, 이 문자열은 i에서 j까지 갔다가 다시 k까지 돌아갈 때 나오는 문자열이다. 경우의 수는 N^3이지만, 매 i,j마다 가능한 k는 유일하기 때문에 실제로 비교할 경우는 N^2이고, 총 N^3 시간에 문제를 풀 수 있다.

#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
using namespace std;
int main()
{
	int T;
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	cin >> T;
	while (T--)
	{
		string s,t;
		cin >> s >> t;
		int i;
		for (i = 0; i < s.size(); i++)
		{
			string re;
			int j;
			for (j = i; j < s.size(); j++)
			{
				re.push_back(s[j]);
				int k;
				string ne=re;
				for (k = j; k >= 0; k--)
				{
					if (k != j)
						ne.push_back(s[k]);
					if (j - i + 1 + j - k == t.size())
					{
						if (t == ne)
						{
							cout << "YES"<<'\n';
							goto T;
						}
					}
				}
			}
		}
		cout << "NO" << '\n';
	T:
		int d;
	}
}

C번: 가능한 경우의 수는 2^10=1024가지이므로 모두 탐색한 다음에 시뮬레이션을 해주면 된다. 1024가지의 상태 탐색은 비트마스크로 쉽게 할 수 있다.

#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
using namespace std;
int main()
{
	int T;
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	cin >> T;
	while (T--)
	{
		string s,t;
		cin >> s >> t;
		int i;
		for (i = 0; i < s.size(); i++)
		{
			string re;
			int j;
			for (j = i; j < s.size(); j++)
			{
				re.push_back(s[j]);
				int k;
				string ne=re;
				for (k = j; k >= 0; k--)
				{
					if (k != j)
						ne.push_back(s[k]);
					if (j - i + 1 + j - k == t.size())
					{
						if (t == ne)
						{
							cout << "YES"<<'\n';
							goto T;
						}
					}
				}
			}
		}
		cout << "NO" << '\n';
	T:
		int d;
	}
}

D번: 핵당했다 ㅠㅠ

E번: k번 돌렸을 때 가능하려면 그 때의 순열이 n-2*m개 이상의 위치에서 맞는 값을 가지고 있어야 한다. 이런 k는 최대 3개 있다. 이런 k에 대해서는 i와 돌려진 pi를 잇는 간선들로 이루어진 그래프를 만들었을 때 정점 개수-컴포넌트 수가 m 이하여햐 한다. 매 원소마다 이 원소를 맞출 수 있는 k값을 찾고, 그런 k값에 대해 탐색을 진행하면 된다.

#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
using namespace std;
int succs[300100];
int arr[300100];
int uf[300100];
int f(int n)
{
	return n == uf[n] ? n : uf[n] = f(uf[n]);
}
int u(int n,int m)
{
	n = f(n);
	m = f(m);
	if (n == m)
		return 0;
	uf[n] = m;
	return 1;
}
int main()
{
	int T;
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	cin >> T;
	while (T--)
	{
		int N, M;
		cin >> N >> M;
		int i;
		for (i = 0; i < N; i++)
		{
			cin >> arr[i];
			arr[i]--;
			succs[(arr[i] - i + N) % N]++;
		}
		vector<int>x;
		
		for (i = 0; i < N; i++)
		{
			if (succs[i] >= (N - 2 * M))
			{
				int ans = 0;
				int j;
				for (j = 0; j < N; j++)
					uf[j] = j;
				for (j = 0; j < N; j++)
				{
					ans+=u((j + i) % N, arr[j]);
				}
				if (ans <= M)
				{
					x.push_back((N-i)%N);
				}
			}
		}
		sort(x.begin(), x.end());
		cout << x.size() << ' ';
		for (i = 0; i < x.size(); i++)
			cout << x[i] << ' ';
		cout << '\n';
		for (i = 0; i < N; i++)
		{
			succs[(arr[i] - i + N) % N]--;
		}
	}
}

F번: 주의: 이 풀이는 정해가 아니며, 시간 제한에 겨우 들어가며, 상수 커팅이 필요하고, 매우 깔끔하지 않다.

1000 정도의 값 K를 잡고, Ai를 K보다 작은 것과 큰 것으로 나눌 수 있다. 이러면, Xi-X(i-1)을 계산할 수 있다.

Xi-X(i-1)은 네 부분으로 나누어진다. Ai%작은 수, Ai%큰 수, 작은 수%Ai, 큰 수%Ai

기본적으로, 작은 수에 대해서는 각각의 작은 수가 몇 번 나오는지 계산을 해 둔다.

Ai가 작을 경우에는, Ai%작은 수는 K보다 작은 모든 수에 대해 나오는 경우*값, Ai%큰 수는 Ai*(I-1), 작은 수%Ai는 Ai%작은 수와 같은 방법, 큰 수%Ai는 큰 수를 처리할 때 모든 작은 수에 대해서 계산한 결과를 참조하면 된다.

Ai가 클 경우에는 Ai%작은수는 Ai와 작은 경우와 똑같이, 작은 수%Ai는 작은 수의 합으로 하면 된다.

Ai%큰 수는 Ai*(i-1)-mod로 인해 지워지는 수로 나눌 수 있고, mod로 인해 지워지는 수는 큰 수가 나올 때마다 Ai~N에서 지워지는 수 +Ai, 2*Ai~N에서 지워지는 수 +Ai로 나타낼 수 있고, 이는 펜윅 트리로 가능하다. 큰 수%Ai는 큰 수들의 합-(Ai~(2*Ai-1))에서의 개수*Ai-(2*Ai-(3*Ai-1))에서의 개수*2Ai....으로 나타낼 수 있고, 이는 펜윅 트리로 가능하다.

시간 복잡도는 Nsqrt(NlogN)으로 추정된다.

코드에서 반복문을 안 쓴 부분이 있는데, 이는 의도적인 최적화를 위한 것이다......

#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
using namespace std;
#define int long long
#define DIV 725
signed ft[5000100];
#pragma GCC target ("avx,avx2")
#pragma GCC optimization ("O3")
#pragma GCC optimization ("unroll-loops")
inline void upd(int n, int k)
{
	while (n <= 300000)
	{
		ft[n] += k;
		n += n & -n;
		ft[n] += k;
		n += n & -n;
		ft[n] += k;
		n += n & -n;
	}
}
inline int get(int n)
{
	int ans = 0;
	ans += ft[n];
	n -= n & -n;
	ans += ft[n];
	n -= n & -n;
	ans += ft[n];
	n -= n & -n;
	ans += ft[n];
	n -= n & -n;
	ans += ft[n];
	n -= n & -n;
	ans += ft[n];
	n -= n & -n;
	ans += ft[n];
	n -= n & -n;
	ans += ft[n];
	n -= n & -n;
	ans += ft[n];
	n -= n & -n;
	ans += ft[n];
	n -= n & -n;
	ans += ft[n];
	n -= n & -n;
	ans += ft[n];
	n -= n & -n;
	ans += ft[n];
	n -= n & -n;
	ans += ft[n];
	n -= n & -n;
	ans += ft[n];
	n -= n & -n;
	ans += ft[n];
	n -= n & -n;
	ans += ft[n];
	n -= n & -n;
	ans += ft[n];
	n -= n & -n;
	ans += ft[n];
	n -= n & -n;
	ans += ft[n];
	n -= n & -n;
	return ans;
}
int ft2[5000100];
inline void upd2(int n, int k)
{
	while (n <= 300000)
	{
		ft2[n] += k;
		n += n & -n;
		ft2[n] += k;
		n += n & -n;
		ft2[n] += k;
		n += n & -n;
	}
}
inline int get2(int n)
{
	int ans = 0;
	ans += ft2[n];
	n -= n & -n;
	ans += ft2[n];
	n -= n & -n;
	ans += ft2[n];
	n -= n & -n;
	ans += ft2[n];
	n -= n & -n;
	ans += ft2[n];
	n -= n & -n;
	ans += ft2[n];
	n -= n & -n;
	ans += ft2[n];
	n -= n & -n;
	ans += ft2[n];
	n -= n & -n;
	ans += ft2[n];
	n -= n & -n;
	ans += ft2[n];
	n -= n & -n;
	ans += ft2[n];
	n -= n & -n;
	ans += ft2[n];
	n -= n & -n;
	ans += ft2[n];
	n -= n & -n;
	ans += ft2[n];
	n -= n & -n;
	ans += ft2[n];
	n -= n & -n;
	ans += ft2[n];
	n -= n & -n;
	ans += ft2[n];
	n -= n & -n;
	ans += ft2[n];
	n -= n & -n;
	return ans;
}
int cousmalls[DIV+1];
int countmod[DIV + 1][DIV+1];
int modcal[DIV + 1][DIV + 1];
signed main()
{
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	int N;
	cin >> N;
	int i,j;
	for (i = 0; i <= DIV; i++)
	{
		for (j = 1; j <= DIV; j++)
		{
			modcal[i][j] = (i % j);
		}
	}
	int su = 0;
	int bigcou = 0;
	int smallsu = 0;
	int bigsu = 0;
	for (i = 1; i <= N; i++)
	{
		int a;
		cin >> a;
		if (a < DIV)
		{
			int j;
			for (j = 1; j ^ DIV; j++)
			{
				su += cousmalls[j] * (modcal[a][j]+modcal[j][a]);
			}
			for (j = 0; j ^ a; j++)
			{
				su += countmod[a][j] * j;
			}
			su += bigcou*a;
			cousmalls[j]++;
			smallsu += a;
		}
		else
		{
			su += smallsu;
			int j;
			for (j = 1; j ^ DIV; j++)
			{
				su += cousmalls[j] * (a%j);
			}
			su += bigsu;
			su += a * bigcou;
			su += get2(a);
			int c = 0;
			int re = get(300000);
			for (j = a; j <= 300000; j += a)
			{
				c++;
				upd2(j, -a);
				su -= (re - get(j - 1))*a;
			}
			for (j = 1; j ^DIV; j++)
			{
				countmod[j][a % j]++;
			}
			upd(a, 1);
			bigsu+=a;
			bigcou++;
		}
		cout << su << ' ';
	}
}
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/04   »
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
글 보관함