백준(C, C++)/플래티넘

백준 2505: 두 번 뒤집기 [C/C++]

치킨먹고싶어요 2022. 6. 3. 14:25

https://www.acmicpc.net/problem/2505

 

2505번: 두 번 뒤집기

첫줄에는 숫자판의 크기를 나타내는 정수 N (5 ≤ N ≤ 10,000)이 주어진다. 그 다음 줄에는 두 개의 구간이 뒤집혀진 놀이판의 상태를 나타내는 숫자들이 하나의 공백을 두고 나타난다. 

www.acmicpc.net

 

#include<bits/stdc++.h>
using namespace std;
 
#define nn 10001
#define f first
#define s second
typedef vector<pair<int,int>> vpii;
 
int n, a[nn], b1[nn], b2[nn];
int m=0, l1=1, r1=1, l2=1, r2=1;
vpii seg;
 
void turn(int l, int r){
    forint i=l; i<=r; i++ ) b2[i] = b1[i];
    forint i=l,j=r; i<=r; i++,j-- ) b1[i] = b2[j];
}
void dfs( int x, vpii now ){
    if( m<0 ) return;
    if( x==2 ){
        vpii tmp = seg;
        int s1 = now[0].f, s2 = now[0].s;
        int L1 = seg[s1].f, R1 = seg[s2].s;
        forint i=1; i<=n; i++ ) b1[i] = a[i];
        
        turn( L1, R1 ); // 첫 번째 뒤집기
        forint i=s1; i<=s2; i++ ){
            tmp[i].f = L1+R1 - tmp[i].f;
            tmp[i].s = L1+R1 - tmp[i].s;
            swap(tmp[i].f,tmp[i].s);
        }
        forint i=0; i<=(s2-s1)/2; i++ ) swap(tmp[s1+i],tmp[s2-i]);
        int L2 = tmp[now[1].f].f, R2 = tmp[now[1].s].s;
        turn( L2, R2 ); // 두 번째 뒤집기
        
        forint i=1; i<=n; i++ ) if( i!=b1[i] ) return;
        m=-1, l1 = L1, r1 = R1, l2 = L2, r2 = R2;
        return;
    }
    forint i=0; i<m; i++ ){
        forint j=i; j<m; j++ ){
            now.push_back({i,j});
            dfs(x+1,now);
            now.pop_back();
        }
    }
}
int main(){
    scanf("%d",&n);
    int l=n+1, r=0;
    forint i=1; i<=n; i++ ){
        scanf("%d",&a[i]);
        if(i!=a[i]) l = min(l,i), r = max(r,i);
    }
    forint i=l; i<=r; i++ ){
        int nl = i, nr = i, j = i+1;
        if( i<r ){
            if( a[i]-1==a[i+1] ){ 
                while( j+1<=&& a[j]-1==a[j+1] ) j++;
                nr = i = j;
            }else if(a[i]+1==a[i+1]){
                while( j+1<=&& a[j]+1==a[j+1] ) j++;
                nr = i = j;
            }
        }
        seg.push_back({nl,nr}); // 뒤집기 후보 구간 추가
        m++;
    }
    if( m==1 ) l1=seg[0].f, r1=seg[0].s;
    else{
        vpii tmp;
        if( m==2 ){ // 예외 케이스를 위한 후보 구간 분할
            if( seg.back().s-seg.back().f==1 ){
                int i = seg.back().f;
                seg.back().s = i;
                seg.push_back({i+1,i+1});  
            }
            if( seg.front().s-seg.front().f==1 ){
                int i = seg.front().f;
                seg.front().s = i;
                seg.push_back({i+1,i+1}); 
            }
            sort(seg.begin(),seg.end());
            m = int( seg.size() );
        }
        dfs(0,tmp); // 후보 구간을 조합하여 모든 두 번 뒤집기에 대한 완전 탐색
    }
    printf("%d %d\n%d %d",l1,r1,l2,r2);
    return 0;
}
cs

 

 

테스트 케이스에 에러가 있는 듯 합니다.

8

7 3 4 5 6 7 1 2

'백준(C, C++) > 플래티넘' 카테고리의 다른 글

백준 14939: 불 끄기  (0) 2022.08.16
백준 1047: 울타리 [C/C++]  (0) 2022.08.13
백준 3163: 떨어지는 개미 [C언어]  (0) 2022.06.03