본문 바로가기

알고리즘/백준 문제 풀이

[C++] 14756번 Telescope

반응형

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


 

26/02/12

 

 

이동 문제와 거의 유사한 문제이다.


 

문제 접근 방식:

 

 

일단 움직일 배열을 뒤집어주자.

이후 각 행 별로 Convolution을 적용하면 행 별끼리의 결과가 나온다.

우리가 구하는 sum은 행 별 연산 결과를 하나의 열에 대해서 더한 것이기 때문에, 그렇게 구한 sum이 문제에서 주어진 $W$보다 클 경우에만 답에 $+1$을 해주면 된다. 


아래는 내가 위의 접근 방식과 같이 작성한 C++ 코드이다. 더보기를 누르면 확인할 수 있다.

더보기
// 14756번 Telescope
// FFT
#include <iostream>
#include <vector>
#include <cmath>

using namespace std;
#define fastio ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define endl '\n'

struct FFT {
    using ld = long double;
    using ll = long long;
    static constexpr ld PI = acosl(-1.0L);
private :
    // HELPER struct
    struct cd {
        ld re, im;
        cd(ld r=0, ld i=0): re(r), im(i) {}
        cd operator + (const cd& o) const { return cd(re+o.re, im+o.im); }
        cd operator - (const cd& o) const { return cd(re-o.re, im-o.im); }
        cd operator * (const cd& o) const { return cd(re*o.re - im*o.im, re*o.im + im*o.re); }
        cd& operator += (const cd& o) { re+=o.re; im+=o.im; return *this; }
        cd& operator -= (const cd& o) { re-=o.re; im-=o.im; return *this; }
        cd& operator *= (const cd& o) { *this = (*this)*o; return *this; }
    };
public : 
    void iterative_FTT(vector<cd>& a, int invert){
        int n = (int)a.size();
        // 1) bit-reversal permutation
        for (int i = 1, j = 0; i < n; i++){
            int bit = n >> 1;
            while (j & bit){
                j ^= bit;
                bit >>= 1;
            }
            j ^= bit;
            if (i < j) swap(a[i], a[j]);
        }
        // 2) butterflies by length = 2, 4, 8, ...
        for (int len = 2; len <= n; len <<= 1){
            ld ang = 2 * PI / len * (invert ? -1 : 1);
            cd w_len(cosl(ang), sinl(ang)); // primitive len-th root of unity on unit circle
            for (int i = 0; i < n; i += len){
                cd w(1, 0);
                for (int j = 0; j < len / 2; j++){
                    cd u = a[i+j];
                    cd v = w * a[i+j+len/2];
                    a[i+j] = u+v;
                    a[i+j+len/2] = u-v;
                    w *= w_len;
                }
            }
        }
        // 3) Divide by n (multiply by inverse) for inverse transform
        if (invert){
            ld inv_n = 1.0L / n;
            for (int i = 0; i < n; ++i){
                a[i].re *= inv_n;
                a[i].im *= inv_n;
            }
        }
    }
    // Input : Coefficient vector {a_0, a_1, ...}, {b_0, b_1, ...}
    // Output : Convolution of two coefficient vector
    vector<ll> convolution(const vector<ll>& a, const vector<ll>& b) {
        if (a.empty() || b.empty()) return {};
        int S_a = (int)a.size(), S_b = (int)b.size();
        // Make vector size easy to dnc(2^n).
        int n = 1;
        while (n < S_a + S_b - 1){
            n <<= 1;
        }
        vector<cd> fa(n), fb(n);
        for (int i = 0; i < S_a; i++) fa[i] = cd((ld)a[i], 0);
        for (int i = 0; i < S_b; i++) fb[i] = cd((ld)b[i], 0);
        // FTT
        iterative_FTT(fa, 0); iterative_FTT(fb, 0);
        // Pointwise product
        for (int i = 0; i < n; i++) fa[i] *= fb[i];
        // IFTT
        iterative_FTT(fa, 1);
        vector<ll> res(S_a + S_b - 1);
        for (int i = 0; i < res.size(); i++) {
            res[i] = (ll) llround(fa[i].re); // rounding to nearest integer
        }
        return res;
    }
};

int main() {
    fastio

    long long N, l, m, W;
    cin >> N >> l >> m >> W;
    vector<vector<long long>> T(m, vector<long long>(N, 0)), P(m, vector<long long>(l, 0));
    for (int i = 0; i < m; ++i){
        for (int j = 0; j < N; ++j){
            cin >> T[i][j];
        }
    }
    for (int i = 0; i < m; ++i){
        for (int j = 0; j < l; ++j){
            cin >> P[i][l-j-1];
        }
    }
    vector<vector<long long>> res;
    FFT fft;
    for (int i = 0; i < m; ++i){
        auto C = fft.convolution(T[i], P[i]);
        res.push_back(C);
    }
    int ans = 0;
    for (int i = l-1; i < N; ++i){
        long long sum = 0;
        for (int j = 0; j < m; ++j){
            sum += res[j][i];
        }
        if (sum > W) ++ans;
    }
    cout << ans;
    return 0;
}
반응형

'알고리즘 > 백준 문제 풀이' 카테고리의 다른 글

[C++] 27897번 특별한 화재 경보  (0) 2026.02.27
[C++] 13055번 K-Inversions  (0) 2026.02.27
[C++] 14958번 Rock Paper Scissors  (0) 2026.02.26
[C++] 11385번 씽크스몰  (0) 2026.02.25
[C++] 13575번 보석 가게  (0) 2026.02.25