結果

問題 No.655 E869120 and Good Triangles
ユーザー qwewe
提出日時 2025-05-14 13:20:24
言語 C++17
(gcc 13.3.0 + boost 1.87.0)
結果
TLE  
実行時間 -
コード長 6,876 bytes
コンパイル時間 1,025 ms
コンパイル使用メモリ 84,020 KB
実行使用メモリ 7,840 KB
最終ジャッジ日時 2025-05-14 13:21:40
合計ジャッジ時間 5,478 ms
ジャッジサーバーID
(参考情報)
judge2 / judge1
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample -- * 3
other AC * 10 TLE * 1 -- * 19
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <iostream>
#include <vector>
#include <queue>
#include <limits>

// Using long long for infinity to handle sums correctly against P_thresh
const long long INF = std::numeric_limits<long long>::max();

struct Point {
    int r, c;
};

// Helper to check if (r, c) is a valid vertex in the N-sized main triangle
bool is_valid_coord(int r, int c, int N) {
    return r >= 1 && r <= N && c >= 1 && c <= r;
}

int main() {
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(NULL);

    int N, K;
    long long P_thresh;
    std::cin >> N >> K >> P_thresh;

    if (K == 0) {
        // All a_i,j are INF. Sum for any triangle is INF.
        // If P_thresh is finite, INF >= P_thresh is true. All triangles are good.
        long long total_triangles = 0;
        for (int r_coord = 1; r_coord <= N; ++r_coord) {
            for (int c_coord = 1; c_coord <= r_coord; ++c_coord) {
                total_triangles += (N - r_coord + 1);
            }
        }
        std::cout << total_triangles << std::endl;
        return 0;
    }

    std::vector<std::vector<long long>> a(N + 1, std::vector<long long>(N + 1, INF));
    std::queue<Point> q;

    for (int i = 0; i < K; ++i) {
        int r_black, c_black;
        std::cin >> r_black >> c_black;
        if (is_valid_coord(r_black, c_black, N)) {
            if (a[r_black][c_black] == INF) { // Avoid re-adding if multiple black points are same
                 a[r_black][c_black] = 0;
                 q.push({r_black, c_black});
            }
        }
    }
    
    // Delta r, Delta c for neighbors
    // (r, c+1), (r, c-1)
    // (r+1, c), (r+1, c+1)
    // (r-1, c), (r-1, c-1)
    int dr[] = {0, 0, 1, 1, -1, -1};
    int dc[] = {1, -1, 0, 1, 0, -1};

    while (!q.empty()) {
        Point curr = q.front();
        q.pop();

        for (int i = 0; i < 6; ++i) {
            int nr = curr.r + dr[i];
            int nc = curr.c + dc[i];

            bool structurally_valid_neighbor = true;
            // Special check for (r-1, c): vertex (row, col) only exists if col <= row.
            // So (curr.r-1, curr.c) is only a parent if curr.c <= curr.r-1.
            if (dr[i] == -1 && dc[i] == 0) { // Trying to move to (curr.r-1, curr.c)
                if (curr.c > curr.r - 1) {
                    structurally_valid_neighbor = false;
                }
            }
            
            if (is_valid_coord(nr, nc, N) && structurally_valid_neighbor) {
                if (a[nr][nc] > a[curr.r][curr.c] + 1) {
                    a[nr][nc] = a[curr.r][curr.c] + 1;
                    q.push({nr, nc});
                }
            }
        }
    }
    
    std::vector<std::vector<long long>> rps(N + 1, std::vector<long long>(N + 1, 0));
    for (int r_coord = 1; r_coord <= N; ++r_coord) {
        for (int c_coord = 1; c_coord <= r_coord; ++c_coord) {
            long long current_a_val = a[r_coord][c_coord];
            if (c_coord == 1) {
                rps[r_coord][c_coord] = current_a_val;
            } else {
                // Propagate INF carefully: finite + INF = INF
                if (rps[r_coord][c_coord - 1] == INF || current_a_val == INF) {
                    if (rps[r_coord][c_coord - 1] != INF && current_a_val == INF) rps[r_coord][c_coord] = INF;
                    else if (rps[r_coord][c_coord - 1] == INF && current_a_val != INF) rps[r_coord][c_coord] = INF;
                    else rps[r_coord][c_coord] = INF; // both INF
                } else {
                     // Check for overflow if adding two large finite numbers, though max finite sum is 6.4e10
                     if (rps[r_coord][c_coord-1] > INF - current_a_val) { // Should not happen with LLONG_MAX
                         rps[r_coord][c_coord] = INF;
                     } else {
                         rps[r_coord][c_coord] = rps[r_coord][c_coord - 1] + current_a_val;
                     }
                }
            }
        }
    }

    long long count_good_triangles = 0;
    for (int r_top = 1; r_top <= N; ++r_top) {
        for (int c_top = 1; c_top <= r_top; ++c_top) {
            long long current_triangle_sum = 0;
            
            for (int s = 1; ; ++s) {
                int base_r = r_top + s - 1;
                if (base_r > N) break; // Sub-triangle exceeds main triangle height

                int base_c_start = c_top;
                int base_c_end = c_top + s - 1;
                // base_c_end must be <= base_r. This is true if c_top <= r_top.
                // If base_c_end > base_r, it means the base of sub-triangle is too wide for its row.
                // This should not happen given c_top <= r_top ensures c_top+s-1 <= r_top+s-1.

                long long new_row_sum_val;
                long long rps_at_end = rps[base_r][base_c_end];
                long long rps_at_start_minus_1 = (base_c_start > 1) ? rps[base_r][base_c_start - 1] : 0;

                if (rps_at_start_minus_1 == INF) { // Implies rps_at_end is also INF
                    new_row_sum_val = INF; // Sum of INFs is INF
                } else if (rps_at_end == INF) { // rps_at_end is INF, but rps_at_start_minus_1 is finite
                    new_row_sum_val = INF;
                } else { // Both are finite
                    new_row_sum_val = rps_at_end - rps_at_start_minus_1;
                }

                if (current_triangle_sum == INF || new_row_sum_val == INF) {
                     if (current_triangle_sum != INF && new_row_sum_val == INF) current_triangle_sum = INF;
                     else if (current_triangle_sum == INF && new_row_sum_val != INF) current_triangle_sum = INF;
                     else current_triangle_sum = INF; // both INF
                } else {
                    if (current_triangle_sum > INF - new_row_sum_val) { // Overflow check
                        current_triangle_sum = INF;
                    } else {
                        current_triangle_sum += new_row_sum_val;
                    }
                }
                
                // Optimization: if current_triangle_sum is already huge (but not INF), cap it.
                // P_thresh can be up to 10^18. LLONG_MAX is ~9e18.
                // Max finite sum is ~6.4e10. This cap is mostly for sums involving INF.
                if (current_triangle_sum != INF && P_thresh > 0 && current_triangle_sum > P_thresh + N + 7) { // Arbitrary margin larger than P
                     current_triangle_sum = P_thresh + N + 7; // Cap to prevent large intermediate sums from slowing down or other issues.
                }


                if (current_triangle_sum >= P_thresh) {
                    int s_max = N - r_top + 1;
                    count_good_triangles += (s_max - s + 1);
                    break; 
                }
            }
        }
    }

    std::cout << count_good_triangles << std::endl;

    return 0;
}
0