A. Pretty Permutations

https://codeforces.com/contest/1541/problem/A

 

Problem - A - Codeforces

 

codeforces.com

 

 1부터 n까지 숫자들은 자기자신에 해당하는 인덱스에 있지 않은 상태 && 각 숫자별 움직이는 횟수 합이 가장 작게 하여 정렬시킬 수 있는 경우를 출력해야한다.

 나같은 경우 n개의 숫자를 n번 움직여서 정렬시키는 문제로 잘못 읽어서 시간을 좀 써버렸다. 아니었으면 세자리 등수 안에 들어갔을 수도..

 

 각설하고 최적의 상태는 2,1,4,3,6,5,... 이런 식으로 홀수 인덱스에 짝수, 짝수 인덱스에 홀수가 들어가있는 상태이다. 만약 저렇게 배열에 저장하고 n=3일 때 출력하면 2,1,4가 나오기 때문에 n이 짝수인 경우 홀수인 경우 나눠서 출력해야한다.

 내가 생각한 최적은 짝수일 때 2,1,4,3,6,5,...n,n1, 홀수일 때 2,1,4,3,6,5,...n,n2,n1이다.

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int INF = 2147483647;

ll gcd(ll a, ll b) { for (; b; a %= b, swap(a, b)); return a; }

int a[101];

int main() {
    ios::ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    for (int i = 0; i < 101; i += 2) a[i] = i + 2;
    for (int i = 1; i < 101; i += 2) a[i] = i;
    
    int T;
    cin >> T;
    while(T--){
        int n;
        cin >> n;
        if (n % 2 == 0) {
            for (int i = 0; i < n; i++) cout << a[i] << ' ';
        }
        else {
            for (int i = 0; i < n - 3; i++) cout << a[i] << ' ';
            cout << n << ' ';
            for (int i = n - 2; i < n; i++) cout << i << ' ';
        }
        cout << '\n';
    }
    return 0;
}

B. Pleasant Pairs

https://codeforces.com/contest/1541/problem/B

 

Problem - B - Codeforces

 

codeforces.com

 완전탐색을 하는데 시간을 줄일 방법을 생각해야했다.

 aiaj=i+j 식을 aj에 대하여 정리해보자.

 aj=i+jai 에서 이미 iai를 안다고 가정하면 aj는 정수이기 때문에 j=xaii가 된다. 

 이제 x을 구해주기 위해 i<j 식을 이용해보면, i<xaii=>x>2i/ai가 된다.

 따라서 x>=2iai를 구할 수 있다.

 결국, j=2iaiaii을 시작으로 +ai를 해주면서 문제 조건에 맞는 i,j인지 확인하면 된다.

 

 이제 시간 복잡도를 생각해보자.

 ai마다 최대 nai번의 연산이 일어난다는 점, 1ai2n인 것과 모든 ai는 distinct하다는 점을 이용하면, 최대

n1+n2+n3+...+n2n=n(11+12+13+...+12n)번의 연산이 일어난다.

 마지막으로 조화 급수를 이용하면 n(11+12+13+...+12n)=nlog(2n)로 식이 정리된다. 따라서 시간복잡도는 O(nlogn)이 된다.

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int INF = 2147483647;

ll gcd(ll a, ll b) { for (; b; a %= b, swap(a, b)); return a; }

int a[100001] = { 0, };

int main() {
    ios::ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
 
    int T;
    cin >> T;
    while(T--){
        int n;
        cin >> n;
        for (int i = 1; i <= n; i++) cin >> a[i];
 
        ll ans = 0;
        for (int i = 1; i <= n; i++) {
            int x = (2 * i) / a[i] + 1; // 올림
            int start = x * a[i] - i;
            
            for (int j = start; j <= n; j += a[i]) {
                if (a[j] == (i + j) / a[i]) ans++;
            }
        }
        cout << ans << '\n';
    }
    return 0;
}

C. Great Graphs

https://codeforces.com/contest/1541/problem/C

 

Problem - C - Codeforces

 

codeforces.com

 입력받은 배열 d를 우선 오름차순으로 정렬시키고 1번부터 n번 목초지가 있다고 생각해보자.

 낮은 번호에서 높은 번호로 가는 도로는 많이 지을수록 total weight cost를 낮추는 데에 도움이 안된다. 반대로 높은 번호에서 낮은 번호로 가는 도로는 많이 지을수록 total weight cost가 낮아지기 때문에 최대한 많이 지어야 한다.

 정리해보면 낮은 번호 -> 높은 번호 도로는 1->n 으로 가는 도로 하나만 짓고, 높은 번호 -> 낮은 번호 도로는 모두 다 지어야 한다. 

 

 B번 문제와 마찬가지로 이중 for문으로 완전탐색을 실시하면 O(n2)이 되므로 TLE에 걸릴 확률이 높다. 자 그러면 문제 해결을 위해 식을 세워보자. n번에서 낮은 번호로 가는 도로들의 weight의 합을 구하는 식을 세우자.

n>1=d1dn

n>2=d2dn

...

n>n1=dn1dn

TotalWeight=(d1+d2+...+dn1)(n1)dn

아! 찾았다. 구간 합을 이용하면 O(1)n번에서 낮은 번호로 가는 모든 도로의 합을 구할 수 있다.

구간 합을 통해 답을 구하는 것이기 때문에 시간 복잡도는 O(n)이 된다.

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int INF = 2147483647;

ll gcd(ll a, ll b) { for (; b; a %= b, swap(a, b)); return a; }

ll d[100001] = { 0, };
ll sum[100001] = { 0, };

int main() {
    ios::ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int T;
    cin >> T;
    while(T--){
        int n;
        cin >> n;
        for (int i = 1; i <= n; i++) cin >> d[i];
        sort(d + 1, d + n + 1);

	for (int i = 1; i <= n; i++) sum[i] = sum[i - 1] + d[i]; // 구간 합
        ll ans = d[n]; // 1 -> n번으로 가는 도로 weight

        for (int i = n; i > 1; i--) {
            ans += (sum[i - 1]) - (i - 1) * d[i];
        }

        cout << ans << '\n';
    }
    return 0;
}

 

'codeforce' 카테고리의 다른 글

Round #731 (Div. 3)  (0) 2021.07.11
Round #727  (0) 2021.06.25
Round #725 (Div. 3)  (0) 2021.06.14
Round #707 (Div. 2)  (0) 2021.05.25
Round #706 (Div. 2)  (0) 2021.05.24

+ Recent posts