結果
| 問題 |
No.1720 Division Permutation
|
| コンテスト | |
| ユーザー |
qwewe
|
| 提出日時 | 2025-05-14 12:57:06 |
| 言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
MLE
|
| 実行時間 | - |
| コード長 | 10,712 bytes |
| コンパイル時間 | 1,459 ms |
| コンパイル使用メモリ | 105,836 KB |
| 実行使用メモリ | 813,528 KB |
| 最終ジャッジ日時 | 2025-05-14 12:59:07 |
| 合計ジャッジ時間 | 8,557 ms |
|
ジャッジサーバーID (参考情報) |
judge2 / judge5 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 3 |
| other | AC * 15 MLE * 1 -- * 44 |
ソースコード
#include <iostream>
#include <vector>
#include <numeric>
#include <algorithm>
#include <functional> // for std::function
using namespace std;
typedef long long ll;
const int MOD = 998244353;
const int INF = 1e9 + 7; // Use a large value to represent infinity initially
// Structure for segment tree node
struct Node {
int min_val = INF; // Minimum value in the node's range
int count = 0; // Count of elements equal to min_val
ll lazy_add = 0; // Lazy tag for range additions
};
vector<Node> tree; // Segment tree
vector<int> p; // Input permutation P
vector<vector<int>> start_indices; // start_indices[e] stores list of start indices s such that P[s..e] is beautiful
// Build an empty segment tree initialized with large values
void build_empty(int node, int start, int end) {
tree[node] = {INF, 0, 0};
if (start == end) {
return;
}
int mid = start + (end - start) / 2;
build_empty(2 * node, start, mid);
build_empty(2 * node + 1, mid + 1, end);
}
// Push lazy tag down to children
void push(int node, int start, int end) {
if (tree[node].lazy_add == 0 || start == end) { // No lazy value or leaf node
if(start == end) tree[node].lazy_add = 0; // Clear lazy at leaf if needed
return;
}
// Apply lazy value to children's lazy tag
tree[2 * node].lazy_add += tree[node].lazy_add;
tree[2 * node + 1].lazy_add += tree[node].lazy_add;
// Clear lazy value of current node
tree[node].lazy_add = 0;
}
// Combine results from children into parent node
// This function computes the node's min_val and count based on children's effective values (considering their lazy tags)
void combine(int node, int start, int end) {
// Calculate effective minimum values of children
int left_min = tree[2 * node].min_val + tree[2 * node].lazy_add;
int right_min = tree[2 * node + 1].min_val + tree[2 * node + 1].lazy_add;
tree[node].min_val = min(left_min, right_min); // Parent's min is the minimum of children's effective mins
tree[node].count = 0;
if (tree[node].min_val == left_min) {
tree[node].count += tree[2*node].count;
}
if (tree[node].min_val == right_min) {
tree[node].count += tree[2*node+1].count;
}
}
// Update range [l, r] by adding add_val
void update_range(int node, int start, int end, int l, int r, int add_val) {
// Current node's effective minimum must be considered before range check logic.
// This calculation is implicit now because lazy tags are pushed down.
if (start > end || start > r || end < l) { // Out of range
return;
}
if (l <= start && end <= r) { // Fully contained range
tree[node].lazy_add += add_val; // Update lazy tag
return; // Don't recurse further, lazy tag handles the update
}
// Partially contained range: push lazy tag down and recurse
push(node, start, end); // Push lazy tag to children BEFORE recursing
int mid = start + (end - start) / 2;
update_range(2 * node, start, mid, l, r, add_val);
update_range(2 * node + 1, mid + 1, end, l, r, add_val);
// After updating children, recompute current node's value
combine(node, start, end);
}
// Update point idx to value val. Value `val` represents the target effective value V_idx.
// The base value stored in the leaf node needs to account for the lazy tag.
void update_point(int node, int start, int end, int idx, int val) {
push(node, start, end); // Push lazy tag down before processing
if (start == end) { // Leaf node
// Store base value such that base_value + lazy_add = val
tree[node].min_val = val - tree[node].lazy_add;
tree[node].count = 1;
return;
}
int mid = start + (end - start) / 2;
// Decide which child to recurse into
if (idx <= mid) {
update_point(2 * node, start, mid, idx, val);
} else {
update_point(2 * node + 1, mid + 1, end, idx, val);
}
// Recompute current node's value based on children
combine(node, start, end);
}
// Query range [l, r] for minimum value and count
pair<int, int> query_range(int node, int start, int end, int l, int r) {
if (start > end || start > r || end < l) { // Out of range
return {INF, 0}; // Return identity element
}
if (l <= start && end <= r) { // Fully contained range
// Return effective minimum value and count
return {tree[node].min_val + tree[node].lazy_add, tree[node].count};
}
// Partially contained range: push lazy tag down, query children and combine
push(node, start, end);
int mid = start + (end - start) / 2;
pair<int, int> p1 = query_range(2 * node, start, mid, l, r);
pair<int, int> p2 = query_range(2 * node + 1, mid + 1, end, l, r);
pair<int, int> res;
res.first = min(p1.first, p2.first);
res.second = 0;
if (res.first == p1.first) {
res.second += p1.second;
}
if (res.first == p2.first) {
res.second += p2.second;
}
return res;
}
vector<int> current_s; // Temporary storage for found indices s
// Recursive function to find all indices `s` in range `[l,r]` where the effective value V_s = 0
void find_zero_indices(int node, int start, int end, int l, int r, ll current_lazy_sum) {
// Calculate effective minimum for this node range considering accumulated lazy tags
ll accumulated_lazy = tree[node].lazy_add + current_lazy_sum;
int effective_min = tree[node].min_val + accumulated_lazy;
// Pruning: if node range is outside query range OR minimum value in node range is > 0, stop.
if (start > end || start > r || end < l || effective_min > 0) {
return;
}
if (start == end) {
// Leaf node within range and check its effective value
if (effective_min == 0) {
current_s.push_back(start);
}
return;
}
// Node range potentially contains 0s, recurse further
int mid = start + (end - start) / 2;
// Pass down the total accumulated lazy tag for children
find_zero_indices(2 * node, start, mid, l, r, accumulated_lazy);
find_zero_indices(2 * node + 1, mid + 1, end, l, r, accumulated_lazy);
}
int main() {
// Fast I/O
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int N;
long long K_ll; // Use long long for K for safety, though problem constraints say K is small
cin >> N >> K_ll;
int K = (int)K_ll; // K <= 10, fits in int
p.resize(N + 1);
for (int i = 1; i <= N; ++i) {
cin >> p[i];
}
// Initialize segment tree
tree.resize(4 * (N + 1));
build_empty(1, 1, N);
start_indices.resize(N + 1); // Adjacency list style storage for beautiful pairs (s, e)
vector<pair<int, int>> stack_max, stack_min; // Stacks for maintaining monotonic properties, store {value, index}
// Main loop iterating through end index `e`
for (int e = 1; e <= N; ++e) {
// Step 1: Account for incrementing `e`. This decreases V_s by 1 for all s < e.
// V_s = M_{s,e} - m_{s,e} + s - e
// When e -> e+1, the term `-e` becomes `-(e+1)`, so V_s decreases by 1.
if (e > 1) {
update_range(1, 1, N, 1, e - 1, -1);
}
// Step 2: Process the current element P[e]
int current_val = p[e];
// Update max stack and perform range updates on segment tree
while (!stack_max.empty() && stack_max.back().first <= current_val) {
pair<int, int> top = stack_max.back();
stack_max.pop_back();
int prev_idx = stack_max.empty() ? 0 : stack_max.back().second;
// Range [prev_idx + 1, top.second] now has max = current_val instead of top.first
// Change in V_s is (current_val - top.first) because M_{s,e} term increases.
if (prev_idx + 1 <= top.second)
update_range(1, 1, N, prev_idx + 1, top.second, current_val - top.first);
}
stack_max.push_back({current_val, e});
// Update min stack and perform range updates on segment tree
while (!stack_min.empty() && stack_min.back().first >= current_val) {
pair<int, int> top = stack_min.back();
stack_min.pop_back();
int prev_idx = stack_min.empty() ? 0 : stack_min.back().second;
// Range [prev_idx + 1, top.second] now has min = current_val instead of top.first
// Change in V_s is -(current_val - top.first) = top.first - current_val because -m_{s,e} term increases.
if (prev_idx + 1 <= top.second)
update_range(1, 1, N, prev_idx + 1, top.second, top.first - current_val);
}
stack_min.push_back({current_val, e});
// Step 3: Set V_e = M_{e,e} - m_{e,e} + e - e = 0. Update segment tree at index e.
update_point(1, 1, N, e, 0);
// Step 4: Query the segment tree for minimum value in range [1, e]. If minimum is 0, find all indices s.
pair<int, int> result = query_range(1, 1, N, 1, e);
if (result.first == 0) { // Check if minimum value is 0
current_s.clear(); // Clear temporary list
find_zero_indices(1, 1, N, 1, e, 0); // Find all indices s in [1,e] where V_s = 0
for (int s : current_s) {
start_indices[e].push_back(s); // Store the pair (s, e)
}
}
} // End of loop finding pairs (s, e)
// Dynamic Programming calculation
vector<vector<ll>> dp(N + 1, vector<ll>(K + 1, 0));
dp[0][0] = 1; // Base case: 0 elements partitioned into 0 subarrays is 1 way
// Iterate through indices i from 1 to N
for (int i = 1; i <= N; ++i) {
// If no beautiful subarrays end at i, dp[i] remains 0, can skip.
if (start_indices[i].empty()) continue;
// Iterate through all start indices `s` such that P[s..i] is beautiful
for (int s : start_indices[i]) {
int j = s - 1; // `j` is the end index of the previous subarray
if (j >= 0) { // Ensure j is valid index (0 to N-1)
// Iterate through possible number of subarrays `x` from 1 to K
for (int x = 1; x <= K; ++x) {
// Add ways to partition P[1..j] into x-1 subarrays
if (dp[j][x-1] > 0) { // Optimization: only add if there's a contribution
dp[i][x] = (dp[i][x] + dp[j][x-1]) % MOD;
}
}
}
}
}
// Output the results for X=1 to K
for (int x = 1; x <= K; ++x) {
cout << dp[N][x] << "\n";
}
return 0;
}
qwewe