AtCoder Beginner Contest 206(Sponsored by Panasonic)
Updated:
A. Maxi-Buying
$\lfloor 1.08 \times N \rfloor$ 값과 206을 비교하는 문제이다.
#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 n;
cin>>n;
int res=1.08*n;
if(res<206) cout<<"Yay!";
else if(res==206) cout<<"so-so";
else cout<<":(";
return 0;
}
B. Savings
돼지 저금통에 $i$번째 날에 $i$엔을 넣을 때, 저금통에 $N$엔보다 많거나 같을 날을 계산하는 문제이다.
$N$의 범위가 $N \le 10^9$이므로 완전탐색할 수 있습니다.
#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);
ll n;
cin>>n;
ll i=1;
while(1) {
ll res=i*(i+1)/2; // 1부터 N까지 더하는 공식
if(res>=n) {
cout<<i;
return 0;
}
i++;
}
return 0;
}
C. Swappable
주어진 배열 $A = (A_1,A_2,…,A_N)$가 있고, 다음 두 조건을 만족하는 $(i,j)$의 수를 구하는 문제이다.
- $A_i \ne A_j$
- $1\le i < j \le N$
예를들면, 1 2 3 1 2 3
이 주어지는 경우 총 12개가 가능하다.
- $(0,1)$, $(0,2)$, $(0,4)$, $(1,5)$
- $(1,2)$, $(1,4)$, $(1,5)$
- $(2,3)$, $(2,4)$
- $(3,4)$, $(3,5)$
- $(4,5)$
여기서 알 수 있는 것은 현재 인덱스보다 뒤로 가면서 본인과 같은 값을 제외한 개수를 더해주고 있다.
그래서 미리 각 원소의 개수를 세어준 후 하나씩 돌면서 (뒤에 남은 원소의 개수 - 현재 가리키는 수와 같은 수의 개수)를 누적해준다.
#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);
map<int,int> m;
for(auto &it : a) {
cin>>it;
m[it]++;
}
ll ans=0;
for(int i=0;i<n-1;i++) {
// cout<<a[i]<<' '<<(n-i-1)-(m[a[i]]-1)<<endl;
ans+=(n-i-1)-(m[a[i]]-1);
m[a[i]]--;
}
cout<<ans;
return 0;
}
D. KAIBUNsyo
주어진 수열이 팰린드롬이 되기 위해 최소 몇번 바꿔야 하는지 계산하는 문제이다.
에디토리얼을 보면 수열들을 그래프로 연결된 것으로 가정하여 해결하고 있다.
- $a_i$와 $a_{n-1-i}$가 연결되어있다고 가정
연결된 노드들이 $k$개의 원소로 구성되어 있다면 $k-1$번의 변환을 통해 같은 원소로 통일할 수 있다.
예를들어 1 5 3 2 5 2 3 1
인 수열이 들어왔다고 가정하면 $(2,3,5)$와 $(1)$이 각각 그래프를 이루고 있다고 할 수 있다.
이때, $(2,3,5)$의 집합은 2번의 연산을 통해 같은 원소로 변환할 수 있고 $(1)$은 연산을 할 필요가 없다. 따라서 위의 수열은 2번만에 팰린드롬으로 만들 수 있다.
DFS나 BFS를 이용해 그래프를 이루는 원소들의 개수를 세어준 후 1을 빼준 값을 누적해서 계산하면 된다. 또한, Disjoint-set을 이용해서 문제를 해결할 수도 있다.
#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;
vector<int> graph[200001];
void dfs(int v, vector<int> &visit, int& count) {
if(graph[v].empty()) return;
visit[v]=1;
for(int next : graph[v]) {
if(!visit[next]) {
visit[next]=1;
count++;
dfs(next,visit,count);
}
}
}
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);
for(auto &it : a) cin>>it;
for(int i=0;i<n/2;i++) {
graph[a[i]].push_back(a[n-i-1]);
graph[a[n-i-1]].push_back(a[i]);
}
vector<int> visit(200001,0);
int ans=0;
for(int i=0;i<n/2;i++) {
if(!visit[a[i]]) {
int count=1;
dfs(a[i],visit,count);
ans+=count-1;
}
}
cout<<ans;
return 0;
}
Comments