백준 단계별 25 그래프와 순회
7562 Knight Moves
1697 Catch That Cow
2178 미로 탐색
1012 유기농 배추
2667 단지번호붙이기
1260 DFS와 BFS
Codeforces #805 Div. 3
https://codeforces.com/contest/1702
결과
언제쯤 4/7의 벽을 통과할까.
A번
주어진 수보다 작은 10^k 중 k의 최댓값을 찾으면 되는 문제다.
void solve(){
int m; cin>>m;
int value = 1000000000;
vector<int> rounds;
while(value >= 1){
rounds.push_back(value);
value /= 10;
}
for(int v : rounds){
if(m - v < 0) continue;
else{
cout<<m - v<<'\n';
return;
}
}
}
B번
simulation 문제. set size가 3보다 작거나, 3인 상황에서 set에 중복된 것이 있다면 insert하고 idx++해주는 간단한 문제.,
void solve(){
string str; cin>>str;
int days = 0, idx = 0, len = str.length();
while(1){
set<char> s;
while(1){
if(s.size() < 3 || s.find(str[idx]) != s.end()){
s.insert(str[idx]);
}
else{
break;
}
idx++;
if(idx >= len){
break;
}
}
days++;
if(idx >= len) break;
}
cout<<days<<'\n';
}
C번
풀이와 내 풀이는 거의 유사하지만... 내 풀이처럼 map의 value에 vector를 넣고, sort할 필요가 없다.
map의 value에 pii를 넣고, .first는 처음 나온 index, .second는 마지막으로 나온 index를 넣고
[m[a] == null || m[b] == null || m[a].first > m[b].second] (시작 정류장의 index가 도착 정류장의 index보다 더 빨라야만 한다)인 경우에 no, 나머지는 true로 해 버리면 된다.
나는 vector sort 후 upper bound를 했는데, m[a].first보다 크기만 하면 되는 거니까 최댓값으로 갱신하면 되는 것이었다.
string yes = "YES\n", no = "NO\n";
void solve(){
int n, k; cin>>n>>k;
map<int, vector<int>> m; // m[i] : station i가 있는 index vector
int station;
for(int i = 0; i<n; i++){
cin>>station;
m[station].push_back(i);
}
for(auto &[key, value] : m){
sort(value.begin(), value.end(), less<int>());
}
int a, b; // a : 시작, b : 도착
string result;
for(int i = 0; i<k; i++){
cin>>a>>b;
if(m[a].size() == 0 || m[b].size() == 0){
result = no;
}
else if(upper_bound(m[b].begin(), m[b].end(), m[a][0]) == m[b].end()){
result = no;
}
else result = yes;
cout<<result;
}
// nlogn 이하
// 지금은 map 썼는데, 좌표 압축을 써야 할지도. 아마 이게 맞는듯?
}
D번
greedy 문제. 현재 cost를 계산하고 cost가 높은 것부터 빼면 된다.
bool cmp(pii &a, pii &b){
if(a.first == b.first) return a.second < b.second;
return a.first > b.first;
}
void solve(){
string w; cin>>w;
int p; cin>>p;
int total_p = 0;
vector<pii> arr(w.length()); // .first : alphabet value, .second : index
for(int i = 0; i<w.length(); i++){
arr[i] = {w[i] - 'a' + 1, i};
total_p += w[i] - 'a' + 1;
}
sort(arr.begin(), arr.end(), cmp);
vector<bool> isDeleted(w.length(), false);
for(pii &elem : arr){
if(total_p <= p) break;
total_p -= elem.first;
isDeleted[elem.second] = true;
}
string result = "";
for(int i = 0; i<w.length(); i++){
if(!isDeleted[i]) result += w[i];
}
cout<<result<<'\n';
}
Upsolving
E번
처음에는 다음과 같이, A에 넣을 수 있으면 넣고, A에 넣을 수 없다면 B에 넣고, 그것도 안 된다면 못 넣는 것으로 간주했다. 그러나 뭔가 반례가 있나 보다.
string no = "NO\n", yes = "YES\n";
bool insertable(pii& domino, vector<bool>& isUsed){
if(domino.first == domino.second) return false;
else if(!isUsed[domino.first] && !isUsed[domino.second]) return true;
else return false;
}
void solve(){
int n; cin>>n; // 짝수
vector<pii> dominos(n); // 1~n까지 수를 포함함
for(pii &domino : dominos){
cin>>domino.first>>domino.second;
domino.first--; domino.second--;
}
// 한쪽에 최대한 넣을 수 있을 만큼 넣고
vector<bool> isUsedA(n, false), isUsedB(n, false);
for(pii &domino : dominos){
if(insertable(domino, isUsedA)){
isUsedA[domino.first] = isUsedA[domino.second] = true;
}
else if(insertable(domino, isUsedB)){
isUsedB[domino.first] = isUsedB[domino.second] = true;
}
else{
cout<<no;
return;
}
}
cout<<yes;
// 이게 왜 동작을 안하는지는 잘 모르겠는데,
// bipartite 검증이라는 생각이 팍 든다. 모든 subgraph가 bipartite then true, else false 감이다.
}
그러고 제출 10분 전에 graph 접근인가..? 싶어서 조금 끄적끄적 했는데, vertex를 1부터 n까지 두고, 각 domino를 edge로 생각하는 것이다. 만약 domino를 정확하게 2개로 나눌 수 있다면 모든 edge color가 달라야 한다, 는 생각이 팍 들어서 bipartite graph 검증이라는 문제 아닐까? 라는 접근을 떠올렸다. bipartite 검증 자체는 쉽다.
string no = "NO\n", yes = "YES\n";
bool isBipartite(int start_node, vector<vector<int>>& edges, vector<int>& colors){
queue<int> q; // vertex number
colors[start_node] = 1;
q.push(start_node);
while(!q.empty()){
int cur = q.front(); q.pop();
for(int adj : edges[cur]){
if(colors[adj] == colors[cur]) return false;
if(colors[adj] == 0){ // unvisited
colors[adj] = 3 - colors[cur]; // red then black, black then red
q.push(adj);
}
}
}
return true;
}
void solve(){
int n; cin>>n; // 짝수
vector<vector<int>> edges(n);
vector<int> colors(n, 0); // 0 : nothing, 1 : red, 2 : black
int from, to;
bool fault = false;
for(int i = 0; i<n; i++){
cin>>from>>to;
from--; to--;
edges[from].push_back(to);
edges[to].push_back(from);
if(edges[from].size() > 2 || edges[to].size() > 2){ ////////////// 여기
fault = true;
}
}
if(fault){
cout<<no;
return;
}
for(int i = 0; i<n; i++){
if(colors[i] == 0){
if(!isBipartite(i, edges, colors)){
cout<<no;
return;
}
}
}
cout<<yes;
return;
// bipartite 검증이라는 생각이 팍 든다. 모든 subgraph가 bipartite then true, else false 감이다.
}
그리고 아래 그림과 같이 반례가 하나 존재하는데, 이렇게 주어지는 경우는 bipartite임에도 불구하고 domino를 나눌 수 없다. 따라서 ////////여기 라고 적힌 부분처럼 작성한다.
F번
이것도 거의 접근 다 한 것 같은데... 일단 내가 처음 했던 접근은 multiset a에 있는 모든 수를 홀수가 될 때까지 나누는 것이다. 이렇게 나누는 근거는 operation이 *2, /2이기 때문에 a가 짝수인 경우 b의 element를 /2해서 맞춰줄 수 있기 때문이다. - 여기까지 접근했었다.
추가로, 해설지 보니까 이렇게 하면 multiset a에 있는 모든 수들은 홀수가 되기 때문에 multiset b의 element에 operation *2를 사용하면 짝수가 되고, 따라서 operation *2는 금지된다.
+, a, b를 multiset이나 map에 담아넣어서 b element가 a에 없다면 /2하고 b에 다시 추가, a에 있다면 빼는 식으로 전개하면 된다.(이걸 못했네..) 이렇게 하면 O(nlogn)으로 풀린다. 너무 아쉽다!
그리고 multiset 사용시, multiset.erase(value)를 해 버리면 multiset에 있는 value 값을 가진 모든 element를 지우기 때문에 iterator로 지워야 한다.
void solve(){
int n; cin>>n;
int ai, bi;
multiset<int> a, b;
for(int i = 0; i<n; i++){
cin>>ai;
while(ai % 2 == 0) ai /= 2;
a.insert(ai);
}
for(int i = 0; i<n; i++){
cin>>bi;
while(bi % 2 == 0) bi /= 2;
b.insert(bi);
} // 나눌 수 있는 최대로 나누기
while(!b.empty()){
int belem = *b.begin();
if(a.find(belem) == a.end()){ // not found in a
if(belem == 0) break; // 만약 b가 0이라면 못 찾은 것
b.erase(b.find(belem));
b.insert(belem/2);
}
else{ // found
b.erase(b.find(belem));
a.erase(a.find(belem));
} // multiset 특 : erase(value) 하면 value값 전부 지워짐. 따라서 iter로 지워야 함
}
cout<<(b.empty()?"YES\n":"NO\n");
}
G1, G2
깨부
'PS > PS Log' 카테고리의 다른 글
22.08.14. 풀었던 문제들 (0) | 2022.08.15 |
---|---|
22.08.13. 풀었던 문제들 (0) | 2022.08.13 |
22.08.11. 풀었던 문제들 (0) | 2022.08.13 |
22.08.10. 풀었던 문제들 (0) | 2022.08.10 |
22.08.09. 풀었던 문제들 (0) | 2022.08.09 |