Codeforces Round 674 (Div.3)

Updated:

A. Floor Number

먼저, $n$≤2이라면, 답은 1이다.

나머지는 $\frac{n-3}{x}+2$를 만족한다. (왜냐하면 3층 이후부터 $x$만큼 차지하기 때문)

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

void solve() {
  int n,x;
  cin>>n>>x;
  if(n<=2) {
    cout<<1<<endl;
    return;
  }
  cout<<(n-3)/x+2<<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. Symmetric Matrix

먼저, $m$이 홀수일 경우 매트릭스를 만들 수 없다.

또한, 타일의 왼쪽 상단과 오른쪽 하단의 값은 중요하지 않는 것을 알 수 있다. (왜냐하면 타일은 대칭이어야 하기 때문)

그래서 오른쪽 상단과 왼쪽 하단의 타일이 같은 경우만 체크하는 것이 필요하다.

#include <iostream>
#include <vector>
using namespace std;

typedef long long ll;

void solve() {
  int n, m;
  cin>>n>>m;
  int mat[100][2][2];
  for(int i=0;i<n;i++) {
    for(int a=0;a<2;a++) {
      for(int b=0;b<2;b++) {
        cin>>mat[i][a][b];
      }
    }
  }
  bool ok=false;
  for(int i=0;i<n;i++) { // 가능한 경우가 한 번이라도 있다면 ok는 true
    ok|=mat[i][0][1]==mat[i][1][0];
  }
  ok&=(m%2==0); // m이 홀수일때 불가능
  if(ok) cout<<"YES"<<endl;
  else cout<<"NO"<<endl;
  return;
}

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

C. Increase and Copy

문제에 주어진 두 가지 연산을 이용하여 배열의 합이 $n$이상이 되게 하는 최소 연산 횟수를 구하는 문제이다.

직관적으로, 가장 먼저 해야할 것처럼 보이는 것은 increase $a$ by 1연산인 것같다. 왜냐하면 결과값을 최대한 크게하기 위해 increase연산을 우선적으로 하고 copy연산을 할 것이다.

이때, $n$의 범위가 $1 ≤ n ≤ 10^9$이기 때문에 $2 \times 10^5$이면 원하는 $n$을 충분히 구할 수 있다.

  • 두 연산(increase, copy)이 존재하기 때문에 $n$을 대략적인 제곱근 값인 $10^5$의 두 배면 충분하다.
  • 즉, $O(\sqrt{n})$이면 가능하다.

하나의 element를 증가한 수 $x$가 있다고 가정하면, $x-1$만큼 increase를 진행해야하고(x ≤ $\sqrt{n}$) $\frac{n-x}{x}$만큼 copy를 진행해야 한다.

따라서, $1 ≤ x ≤ min(10^5,n)$ 범위 내에서 $(x-1)+(\frac{n-x}{x})$의 최솟값을 찾으면 된다.

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

typedef long long ll;

void solve() {
  int n;
  cin>>n;
  int ans=(int)1e9;
  for(int x=1;x<=100000 && x<=n;x++) { // min(10^5,n)만큼 i탐색
    // for(int x=1;x*x<=n;x++) 도 가능
    ans=min(ans,(x-1)+((n-1/x)));
  }
  cout<<ans<<endl;
}

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

D. Non-zero Segments

editorial을 봐도 이해가 잘 안가는 문제다.

배열 $a$에 대해 어떠한 subsegments에 대해서도 0이 되게 하지 않는 수를 찾는 문제이다.

먼저, $p_i$를 처음부터 $i$번째까지의 합이라 하자.

구간 $[l;r]$에서의 누적합이 0이라면, $p_r-p_{l-1}$이 0이고 또는 $p_{l-1}=p_r$이다.

왼쪽에서 오른쪽으로 원소들을 돌면서 모든 누적합들을 set에 저장한다.

만약, 현재 누적합이 set에 이미 저장되어 있다면, 합이 0이되는 누적합이 존재하는 것을 알 수 있다.

  • $a+b+c = b+c+d$ 라면, $b+c$는 0임을 알 수 있다.

현재 원소를 기준으로 왼쪽의 모든 누적합보다 크게 되도록 현재 원소 앞에 큰 숫자를 삽입한다. 이제 왼쪽의 모든 누적합 set들을 지우고 위 과정을 다시 반복한다.

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

typedef long long ll;

void solve() {
  int n;
  cin>>n;
  vector<int> a(n);
  for(int i=0;i<n;i++) cin>>a[i];
  set<int> d;
  d.insert(0);
  int cur=0;
  int ans=0;
  for(int i=0;i<n;i++) {
    cur+=a[i];
    if(d.find(cur)!=d.end()) {
      ans+=1;
      d.clear();
      d.insert(0);
      cur=a[i];
    }
    d.insert(cur);
  }
  cout<<ans<<endl;
  return;
}

int main() {
  ios::sync_with_stdio(0);
  //freopen("input.txt","r",stdin);
  solve();
  return 0;
}

Leave a comment