AISing Programming Contest 2021(AtCoder Beginner Contest 202)
Updated:
A. Three Dice
3개의 주사위를 굴렸을 때 윗면에 있는 숫자를 보고 밑면의 숫자를 더하는 문제이다.
(1,6), (2,5), (3,4)가 맞은편에 있는 것을 구현하면 된다.
#include <iostream>
#include <cstring>
#include <vector>
#include <algorithm>
#define endl '\n'
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
const ll INF=1e10+1;
int main(){
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
//freopen("input.txt","r",stdin);
int ans=0;
for(int i=0;i<3;i++) {
int a;
cin>>a;
if(a==1) ans+=6;
else if(a==2) ans+=5;
else if(a==3) ans+=4;
else if(a==4) ans+=3;
else if(a==5) ans+=2;
else ans+=1;
}
cout<<ans;
return 0;
}
B. 180°
0, 1, 6, 8, 9
로 이루어진 문자열 S
를 180도 뒤집었을 때 나타나는 문자열을 출력하는 문제이다.
180도 뒤집었을 때 6 -> 9
, 9 -> 6
으로 바뀌는 것만 처리해주면 된다.
#include <iostream>
#include <cstring>
#include <vector>
#include <algorithm>
#define endl '\n'
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
const ll INF=1e10+1;
int main(){
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
//freopen("input.txt","r",stdin);
string s;
cin>>s;
string ans="";
for(int i=s.size()-1;i>=0;i--) {
char c=s[i];
if(c=='6') ans+='9';
else if(c=='9') ans+='6';
else ans+=c;
}
cout<<ans;
return 0;
}
C. Made Up
주어진 A, B, C 배열에서 $A_i=B_{C_j}$를 만족하는 $(i,j)$의 수를 구하는 문제이다.
$N$의 범위가 $1≤N≤10^5$이므로 $O(N^2)$의 시간 복잡도를 가져서는 안된다.
그래서 B와 C를 map
을 통해 미리 $B_{C_j}$의 수를 계산해놓았다.
#include <iostream>
#include <cstring>
#include <vector>
#include <algorithm>
#include <map>
#define endl '\n'
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
const ll INF=1e10+1;
int main(){
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
//freopen("input.txt","r",stdin);
int n;
cin>>n;
vector<int> a(n+1), b(n+1), c(n+1);
map<int,int> bm;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++) cin>>b[i];
for(int i=1;i<=n;i++) {
cin>>c[i];
bm[b[c[i]]]++;
}
// for(auto it : bm) cout<<it.first<<' '<<it.second<<endl;
ll ans=0;
for(int am : a) {
if(b[am]!=0) ans+=bm[am];
}
cout<<ans;
return 0;
}
D. aab aba baa
‘a’를 A
번, ‘b’를 B
번 반복하여 만들 수 있는 모든 문자열 중 사전식 순서로 정렬했을 때, K
번째 문자열을 출력하는 문제이다.
만약, ‘a’로 시작하는 문자열의 수가 K
보다 같거나 많다면 우리가 찾고자 하는 문자열은 ‘a’로 시작하는 것이 맞다. K
보다 작다면 ‘b’로 시작한다.
예를들어, 3개의 ‘a’와 1개의 ‘b’를 가지고 2번째 문자열을 찾으려고 한다.
- 이때, 앞이 a로 시작하여 남은 문자들로 만들 수 있는 문자열은
aab
,aba
로 2개이다. 따라서, 첫 번째 문자는 ‘a’가 확실하다. - 다음 1개의 ‘a’와 1개의 ‘b’를 가지고 2번째 문자열을 찾으려고 한다. 이때,
ab
로 1개의 문자열을 만들 수 있으므로 다음 글자는 ‘b’가 확실하다. - 남은 글자 ‘a’를 뒤에 붙이면
aaba
가 우리가 찾고자하는 문자열이다.
그럼 ${}_i \mathrm{C}_j$ 를 $C(i,j)$ 라 표현하고 $S(i,j,k)$를 ‘a’를 i
번, ‘b’를 j
번 사용하여 만든 문자열 중 사전식 순서로 k
번째 문자열이라고 가정하자.
다음의 조건을 반복하여 K
번째 문자열을 찾을 수 있다.
- if $i = 0$, $j$ 번 반복한 ‘b’
- if $j = 0$, $i$ 번 반복한 ‘a’
- if $i>0, j>0$
- if $C(i-1,j) ≥ k$, ‘a’ + $S(i-1,j,k)$
- if $C(i-1,j) < k$, ‘b’ + $S(i,j-1,k-dp[i-1][j])$
#include <iostream>
#include <cstring>
#include <vector>
#include <algorithm>
#define endl '\n'
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
const ll INF=1e10+1;
ll dp[31][31];
string find_string(int a,int b,ll k) {
if(a==0) {
string tmp="";
while(b--) tmp+='b';
return tmp;
}
if(b==0) {
string tmp="";
while(a--) tmp+='a';
return tmp;
}
if(k<=dp[a-1][b]) {
return "a"+find_string(a-1,b,k);
}
else {
return "b"+find_string(a,b-1,k-dp[a-1][b]);
}
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
//freopen("input.txt","r",stdin);
int a,b;
ll k;
cin>>a>>b>>k;
// dp[i][j] = a를 i개 뽑고 b를 j개 뽑을 때 만들 수 있는 문자열의 경우의 수
dp[0][0]=1;
for(int i=0;i<=a;i++) {
for(int j=0;j<=b;j++) {
if(i>0) dp[i][j]+=dp[i-1][j];
if(j>0) dp[i][j]+=dp[i][j-1];
}
}
cout<<find_string(a,b,k);
return 0;
}
Comments