728x90
결과
링크 2023.05.25 DIV2
4솔, 3725/16830 (22.1%) 1611 (-69)
(퍼포1353)
오랜만에 망친 대회. D를 4000명이 풀었는데 내가 8트만에 풀어서 퍼포가 작살이 났다. C까지 20분대에 풀어버려서 D도 빨리 풀어야 한다는 압박감에 실수를 한 것 같다.
A Grasshopper on a Line
개요
00:02:00
수학
k로 나누어 떨어지지 않으면서 x까지 이동하는 최소한의 방법 출력
접근
- A,B,C까지 쉽다. 나누어 떨어지지 않는 방법으로 가야 하니까 만약 x가 k의 배수가 아니면? x만큼 이동하고, k의 배수라면 k의 배수가 아닌 서로 다른 두 수의 합으로 나타내면 된다.
- 어차피 k가 2 이상이므로 x-1과 1로 나타내면 간단하게 해결할 수 있다.
Source code
#include <bits/stdc++.h>
using namespace std;
void test() {
int x,k;
cin>>x>>k;
if (x%k) cout<<1<<"\n"<<x<<"\n";
else cout<<2<<"\n"<<x-1<<" "<<1<<"\n";
}
B Comparison String
개요
00:23:06
수학, 구성적
부등호 방향에 맞게 숫자를 구성했을 때 서로 다른 수의 개수가 최소한이 되도록 구성하기
접근
- TC오류로 조금 절었다. 대회 도중 테케가 수정되는 건 처음 본 요상한 문제. 일단 문제의 핵심은 연속된 같은 부등호의 최대 개수가 된다. 왜냐하면 그래프를 그린다고 할 때, 나머지는 구간은 최대 길이 구간 안에 있는 수로 모두 구성할 수 있다.
- 서로 다른 수라는 개념에 집착하지 않고 1씩 차이 난다고 생각하고 접근하면 크게 어렵지 않다.
Source code
#include <bits/stdc++.h>
using namespace std;
void test() {
int n;
str s;
cin>>n>>s;
int c=0,m=0;
for (int i=0;i<n;i++) {
c=1;
while (i<n&&s[i]==s[i+1]) {
c++;
i++;
}
m=max(c,m);
}
cout<<1+m<<"\n";
}
C Best Binary String
개요
00:20:35
String, Greedy
?를 0또는 1로 대체하여 사전순으로 배열하기 위해 연속 부분문자열을 뒤집는 횟수를 최소한으로 만들기
접근
- 문제가 엄청 어려워 보이는데 그렇지 않다. 일단 뒤집는 것을 최소로 하려면 연속된 구간의 길이가 최대한 길어야 한다. 0과 1이 너무 많이 반복되면 뒤집을 일이 많아진다.
- 그럼 0과 0 사이의 물음표는 전부 0, 1과 1은 1로 만들면 되고, 0과 1은 어떻게 하냐? 그냥 앞의 것을 따라주면 된다. 어차피 0과 1 사이에 물음표를 어떤 방식으로 채워도 한번의 뒤집기는 추가되어야 한다.
Source code
#include <bits/stdc++.h>
using namespace std;
using str=string;
#define sz size
void test() {
str s,ans;
cin>>s;
int n=s.sz();
s='0'+s; //앞은 무조건 0이 오는게 이득
ans=s;
int ch=0;
for (int i=1;i<=n;i++) {
// 앞이 무엇이냐?
if (s[i-1]=='0') {
ch=0;
} else if (s[i-1]=='1') {
ch=1;
}
while(s[i]=='?') {
ans[i]=ch+'0'; // 앞의 것을 따라감
i++;
}
}
ans=ans.substr(1);
cout<<ans<<"\n";
}
D Bracket Coloring
개요
01:49:21
구성적, Greedy
Regular하고 beautiful한 괄호를 만들면서 최소한의 종류로 괄호를 분류하기
접근
- 티어를 떨굴뻔한 주범. 확실히 다른 대회의 D보다는 쉬웠고, 그럼에도 나는 잘 못 풀었다. 골3 쯤 수준인데 내가 골랜디를 잘 안해서 이런 문제를 잘 못푼다. 패널티가 234인데 7번 제출을 안하고 1트에 맞았으면 164, 퍼포는 1525쯤 나온다. 어차피 랭크 점수는 떨어졌겠지만 한 20점 정도만 떨구지 않았을까...
- 문제 접근은 이렇게 해주면 간단하다. 먼저 문제를 차분히 이해하는 것이 필요한데,
- Regular하다는 것은 열린 괄호가 제 때에 모두 닫히기만 하면 된다. 먼저 닫힌다에 대해 생각하면, "("를 +1, ")"를 -1이라 하고 전체 문자열을 더했을 때 0이 되면 된다. 그리고 제 때에 닫힌다 라는 건 뭐냐? 하면 ")"가 "("보다 먼저 나오면 안된다는 것이다. 열지도 않았는데 닫으면 안된다는 것이다. 그럼 값을 더해줄 때 음수가 나오면 안된다.
- 문제는 Beautiful인데, 뒤집었을 때 regular 하면 된다. 이번에는 먼저 닫은 다음에 열려도 된다. 그럼 여기서 뒤집는다에 대해 잘 이해하는 것이 매우 중요한데, 위에서 "("는 +1, ")"는 -1로 설정하고 구하는 누적합을 그래프로 나타내보자.
- 아래 길이 24짜리 예시에 대해 그래프를 그려보자.
)))())((((()((()()))))((
- 그래프로 나타내니 직관적으로 변했다. 이때 우리가 경계할 부분은 빨간색 부분, 즉 음수가 나오는 부분이다.
- 이 부분을 뒤집어 regular하게 만들어주려면 사실 그래프를 90도 회전해 위로 올려주면 된다.
단순히 대칭이동해서 뒤집는 것이 아니라 90도 회전한다는 개념이 생각하기 어려운데 이 부분만 이해하면 이 문제는 아주 쉽게 끝난다. - 음수인 부분을 모두 뒤집어주면 다음은 음수는 음수끼리, 양수는 양수끼리 이어 붙여주면 된다. 그래서 최대 색깔의 개수는 음수 한 개, 양수 한 개로 두 개가 된다.
음수와 양수가 변하는 지점을 찾는 것이 중요하므로 1832C와 매우 유사한 문제가 되겠다. 그래프를 그리는데에 사용한 엑셀파일을 첨부한다.1837D.xlsx
20.1 kB
Source code
#include <bits/stdc++.h>
using namespace std;
using vec=vector<int>;
void test() {
int n; str s;
cin>>n>>s;
vec c(n+1,1),a(n+1,0);
int v=0;
for (int i=0;i<n;i++) {
v+=s[i]=='('?1:-1;
a[i]=v;
}
if (v) {
cout<<-1<<"\n";
return;
}
int d=s[0]=='(',t=1,ans=1;
for (int i=0;i<n;i++) {
if (a[i]<0&&d||a[i]>0&&!d) {
t=3-t,d=!d,ans=2;
}
c[i]=t;
}
cout<<ans<<"\n";
for (int i=0;i<n;i++)
cout<<c[i]<<" ";
cout<<"\n";
}
728x90
'코드포스 > Rated' 카테고리의 다른 글
Codeforces Round 874 (0) | 2023.05.20 |
---|---|
Educational Codeforces Round 148 (0) | 2023.05.13 |
Codeforces Round 872 (0) | 2023.05.09 |
Codeforces Round 858 (0) | 2023.03.22 |
Codeforces Round 852 (0) | 2023.02.13 |
Codeforces Round 851 (0) | 2023.02.10 |
Codeforces Round 848 (0) | 2023.02.08 |
TypeDB Forces 2023 (0) | 2023.02.08 |
댓글