문제

https://www.acmicpc.net/problem/17163

 

17163번: 가희의 수열놀이 (Large)

첫 번째 줄에는 쿼리의 수를 의미하는 정수 Q와 나누는 정수 mod 가 공백으로 구분되어 주어집니다. (1 ≤ Q ≤ 106, 1 ≤ mod ≤ 2×109) 이후 Q개의 줄에 걸쳐서, 다음 세 종류의 쿼리 중 하나가 주어집니다. 이는 맨 앞에 오는 정수의 값 (1, 2, 3)에 따라 구분됩니다. 1 num : 수열 arr의 맨 뒤에 num을 추가한다. (1 ≤ num ≤ 231-1) 2 : 수열 arr의 맨 뒤에 있는 원소를 제거한다. 만약 arr이 비어

www.acmicpc.net

 

풀이

만약 mod가 query개수 보다 많다면 항상 불가능하므로, -1을 출력한다.

 

mod가 query개수보다 작은 경우에는 0~mod-1까지의 index를 가지는 stack을 만들어보자.

그리고 숫자가 새로 들어올때 마다, 해당하는 나머지를 index로 가지는 stack에 현재 arr의 원소의 개수를 넣어준다.

3 query가 들어왔을 때, 각 나머지 별로 stack의 top에 있는 숫자의 min값이 우리가 찾는 index가 되고, 전체 사이즈에서 찾은 값을 빼주면 답이 된다.

 

이 방식으로 구하면 $O(q\times mod)$의 시간복잡도가 걸리지만 segment tree를 이용하면 $O(mod+q log mod)$의 시간복잡도로 원하는 답을 구할 수 있다.

 

Time Complexity : $O(mod+q log mod)$

 

코드

#include<iostream>
#include<vector>
#include<stack>
#define N 1000000
#define INF 1<<30
using namespace std;

stack<int, vector<int> > S;
stack<int, vector<int> > rem[N];

int seg[1<<21];
int p, q, mod;

void update(int t)
{
	t+=p;
	while(t!=1)
	{
		t>>=1;
		seg[t] = min(seg[t<<1], seg[t<<1|1]);
	}
}
int main()
{
	cin.tie(NULL);
	cin.sync_with_stdio(false);
	cin>>q>>mod;
	for(p=mod;p^(-p&p);p+=(-p&p));

	if(mod>q)
	{
		while(q--)
		{
			int x;
			cin>>x;
			if(x==3) cout<<-1<<"\n";
			if(x==1) cin>>x;
		}
		return 0;
	}

	for(int i=p;i<p<<1;i++) seg[i]=i<p+mod?-1:INF;
	for(int i=p-1;i>0;i--) seg[i] = min(seg[i<<1],seg[i<<1|1]);
	while(q--)
	{
		int x;
		cin>>x;
		if(x==1)
		{
			cin>>x;
			int t=x%mod;
			S.push(t);
			rem[t].push(S.size());
			seg[p+t]=S.size();
			update(t);
		}
		else if(x==2)
		{
			if(S.empty())continue;
			int t = S.top();
			S.pop();
			rem[t].pop();
			seg[p+t]=rem[t].empty()?-1:rem[t].top();
			update(t);
		}
		else
		{
			if(seg[1]==-1) cout<<"-1\n";
			else cout<< S.size()-seg[1]+1<<"\n";
		}
	}
}

'PS > BOJ' 카테고리의 다른 글

[BOJ] 16000. 섬  (0) 2019.05.06
[BOJ] 5698. Tautogram  (0) 2019.05.06
[BOJ] 9521. 색칠 공부  (2) 2019.05.06
[BOJ] 1734. 교통 체계  (0) 2019.05.02
[BOJ] 1849. 순열  (0) 2019.05.01

+ Recent posts