Educational Codeforces Round #96 (Div.2)

A. Number of Apartments


방이 3개, 5개, 7개짜리로 구성된 아파트에서 각각의 방의 개수를 구하는 문제

가장 간단하게, nn이 1, 2, 4로 구성된 아파트인 경우 방의 개수가 맞지 않으므로 -1을 출력해야 한다.

방 3개를 기준으로 [3,6,9,..][3,6,9,..]

즉, 위의 수열 중 1, 2, 4를 제외하고 모두 표현할 수 있으므로 다음의 경우를 생각할 수 있다.

  • nn이 3으로 나누어 떨어지는 경우, 방 3개짜리로 구성된 아파트이므로 (n/3,0,0)(n/3,0,0)
  • nn을 3으로 나누어 나머지 1이 남는 경우, 방 7개 하나와 나머지 방 3개짜리 이므로, ((n7)/3,0,1)((n-7)/3,0,1)
  • nn을 3으로 나누어 나머지 2가 남는 경우, 방 5개 하나와 나머지 방 3개짜리 이므로, ((n5)/3,1,0)((n-5)/3,1,0)
#include <iostream>
#include <algorithm>
#define endl '\n'
using namespace std;

typedef long long ll;

void solve() {
  int n;
  cin>>n;
  if(n==1 || n==2 || n==4) {
    cout<<-1<<endl;
    return;
  }
  if(n%3==0) {
    cout<<(n/3)<<' '<<0<<' '<<0<<endl;
  }
  else if(n%3==1) {
    cout<<((n-7)/3)<<' '<<0<<' '<<1<<endl;
  }
  else {
    cout<<((n-5)/3)<<' '<<1<<' '<<0<<endl;
  }
  return;
}

int main() {
  ios::sync_with_stdio(0);
  cin.tie(0); cout.tie(0);
  //freopen("input.txt","r",stdin);
  int t;
  cin>>t;
  while(t--) {
    solve();
  }
  return 0;
}

B. Barrels


nn개의 배럴이 일렬로 나열되어 있고 각 배럴에 물은 aia_i

두 배럴을 선택해 물을 옮기면 한 쪽은 무조건 0이 된다. 따라서, 가장 많은 물부터 k번째 물까지 합하면 최대 차를 구할 수 있다.

#include <iostream>
#include <vector>
#include <algorithm>
#define endl '\n'
using namespace std;

typedef long long ll;

void solve() {
  int n, k;
  cin>>n>>k;
  vector<ll> a(n);
  for(int i=0;i<n;i++) cin>>a[i];
  sort(a.begin(),a.end());
  reverse(a.begin(),a.end());
  ll sum=0;
  for(int i=0;i<=k;i++) sum+=a[i];
  cout<<sum<<endl;
  return;
}

int main() {
  ios::sync_with_stdio(0);
  cin.tie(0); cout.tie(0);
  //freopen("input.txt","r",stdin);
  int t;
  cin>>t;
  while(t--) {
    solve();
  }
  return 0;
}

C. Numbers on Whiteboard


1,2,3,...,n1, 2, 3, ..., n

n1n-1

이 문제는 그리디로 해결할 수 있다.

n1n-1

그리고, 모든 수열에 대해 오른쪽에서 왼쪽으로 두 개의 수를 순차로 선택해서 2를 만들 수 있다.

#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
#define endl '\n'
using namespace std;

typedef long long ll;

void solve() {
  int n;
  cin>>n;
  cout<<2<<endl;
  int a=n,b=n-1;
  for(int i=0;i<n-1;i++) {
    cout<<a<<' '<<b<<endl;
    if((a+b)%2==1) a=(a+b)/2+1;
    else a=(a+b)/2;
    b--;
  }
  return;
}

int main() {
  ios::sync_with_stdio(0);
  cin.tie(0); cout.tie(0);
  freopen("input.txt","r",stdin);
  int t;
  cin>>t;
  while(t--) {
    solve();
  }
  return 0;
}

D. String Deletion


임의의 숫자를 지우게 될 때 2개 이상의 같은 숫자끼리는 지워지는 문자열에서 비어있게 될 때까지 최대 연산의 횟수를 구하는 문제

중간에 있는 숫자를 지우게 될 때, 다음 두 가지 경우가 생긴다.

  • 101에서 0을 지우게 되면서, 11이 붙어 같이 지워지는 경우
  • 101에서 맨 앞 1을 지우게 되면서, 01이 되어 조건에 의해 0이 지워지는 경우

최대한 많은 연산을 하기 위해 첫번째 경우를 피해야 한다.

즉, 앞에서부터 2개 이상의 문자열을 먼저 지우고 남은 문자열을 앞에서부터 하나씩 지워가면 된다.

#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
#define endl '\n'
using namespace std;

typedef long long ll;
typedef pair<int,int> pii;

void solve() {
  int n;
  cin>>n;
  string s;
  cin>>s;
  queue<int> q;
  int cur=0;
  for(int i=0;i<n;i++) { // 연속되는 문자열의 위치를 저장
    if(i>0 && s[i]==s[i-1]) q.push(cur);
    if(i>0 && s[i]!=s[i-1]) cur++;
  }
  int deleted=0; // 지워진 연속된 문자열의 문자 개수
  int score=0; // 횟수
  for(int i=0;i<n;i++) {
    if(q.empty()) break;
    q.pop();
    deleted++;
    score++;
    while(!q.empty() && q.front()==i) { // 연속되는 문자열을 지우는 과정
      q.pop();
      deleted++;
    }
    deleted++;
  }
  score+=(n-deleted+1)/2; // 10의 경우 1을 지우면 그 다음 문자도 지워지므로 남은 문자열을 2로 나눈다
  cout<<score<<endl;
  return;
}

int main() {
  ios::sync_with_stdio(0);
  cin.tie(0); cout.tie(0);
  //freopen("input.txt","r",stdin);
  int t;
  cin>>t;
  while(t--) {
    solve();
  }
  return 0;
}

좋은 웹페이지 즐겨찾기