Submission #312137

#TimeUsernameProblemLanguageResultExecution timeMemory
312137chctxdy68Split the sequence (APIO14_sequence)C++14
79 / 100
416 ms83832 KiB
#include <bits/stdc++.h> #include <ext/pb_ds/assoc_container.hpp> #include <ext/pb_ds/tree_policy.hpp> #pragma GCC optimize ("Ofast") #pragma GCC optimization ("unroll-loops, no-stack-protector") #pragma GCC target ("avx") #pragma GCC target ("avx2") #pragma GCC target ("fma") #define fastio ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0) #define ll long long #define ull unsigned long long #define ld long double #define pii pair <int, int> #define pll pair <ll, ll> #define pci pair <char, int> #define pld pair <ld, ld> #define ppld pair <pld, pld> #define ppll pair <pll, pll> #define pldl pair <ld, ll> #define vll vector <ll> #define vvll vector <vll> #define vpll vector <pll> #define pb push_back #define eb emplace_back #define mp make_pair #define fi first #define se second #define mll map <ll, ll> #define fastmap gp_hash_table #define cd complex <double> #define vcd vector <cd> #define PI 3.14159265358979 #define ordered_set tree <ll, null_type, less <ll>, rb_tree_tag, tree_order_statistics_node_update> #pragma 03 using namespace std; using namespace __gnu_pbds; mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count()); // the real solution is quite hard to implement (two pointers on convex hull), even if I knew how to solve this problem. // (problem 1 is solved by using the observation that there's only n distinct // palindromic substrings in a string of length n, and then use a map of hashes.) // still, the heuristic worked surprisingly well, so I'll see if I can optimize to make it work. // I'll comment my code to make it understandable. ll dp[100005][2]; // dp[i][j]: the best way to partition prefix of length i into j parts. int trace[100005][205]; // trace[i][j]: just a trace to calculate dp. ll a[100005], prefix[100005]; // ... ll patrol[30], seg[30], seg_size; // patrol[i]: current index of "patrol" pointer i, seg[i]: bound for patrol i, seg_size: size of the segment that they'll be patrolling. int main(){ fastio; ll n, k; cin >> n >> k; k++; for (ll i = 1; i <= n; i++) cin >> a[i]; for (ll i = 1; i <= n; i++) prefix[i] = prefix[i - 1] + a[i]; for (ll i = 1; i <= n; i++) dp[i][1] = (prefix[i] * prefix[i]); if (n <= 1000){ // the brute force solution. this works is something like (n ^ 2 * k) / 6, // and even with a bad constant it should be fast enough. for (ll l = 2; l <= k; l++){ ll now = l % 2, prv = now ^ 1; for (ll i = l; i <= n; i++){ dp[i][now] = 1e18; for (ll j = l - 1; j < i; j++){ ll calc = dp[j][prv] + (prefix[i] - prefix[j]) * (prefix[i] - prefix[j]); if (dp[i][now] > calc){ dp[i][now] = calc; trace[i][l] = j; } } } } } else if (n > 10000){ // first heuristic (made by my wrong observation that the function will be convex): two pointers to find the minima. // still, this managed to pass the last subtask, which is certainly saying something about it's efficiency. for (ll l = 2; l <= k; l++){ ll ptr = l - 1; ll now = l % 2, prv = now ^ 1; for (ll i = l; i <= n; i++){ while ((ptr < i - 1) && (dp[ptr][prv] + (prefix[i] - prefix[ptr]) * (prefix[i] - prefix[ptr]) >= dp[ptr + 1][prv] + (prefix[i] - prefix[ptr + 1]) * (prefix[i] - prefix[ptr + 1]))) ptr++; dp[i][now] = dp[ptr][prv] + (prefix[i] - prefix[ptr]) * (prefix[i] - prefix[ptr]); trace[i][l] = ptr; } } } else{ // second heuristic (a small improvement over the previous heuristic): // we create "patrol" pointers: pointers that are supposed to find the minima of a segment. // it functions in basically the same way as the pointer in the first heuristic, except that it should be able // to find some more "deep" positions while runs a lot slower. (25x) seg_size = n / 25 + (n % 25 != 0); for (ll i = 0; i < 25; i++) seg[i] = (i + 1) * seg_size - 1; for (ll l = 2; l <= k; l++){ for (ll i = 0; i < 25; i++){ if (i * seg_size <= l - 1) patrol[i] = l - 1; else patrol[i] = i * seg_size; } ll now = l % 2, prv = now ^ 1; for (ll i = l; i <= n; i++){ dp[i][now] = 1e18; for (ll p = 0; p < 25; p++){ while ((patrol[p] < min(seg[p], i - 1)) && (dp[patrol[p]][prv] + (prefix[i] - prefix[patrol[p]]) * (prefix[i] - prefix[patrol[p]]) >= dp[patrol[p] + 1][prv] + (prefix[i] - prefix[patrol[p] + 1]) * (prefix[i] - prefix[patrol[p] + 1]))) patrol[p]++; ll calc = dp[patrol[p]][prv] + (prefix[i] - prefix[patrol[p]]) * (prefix[i] - prefix[patrol[p]]); if (dp[i][now] > calc){ dp[i][now] = calc; trace[i][l] = patrol[p]; } } } } } cout << (prefix[n] * prefix[n] - dp[n][k % 2]) / 2 << "\n"; ll cur = n; for (ll l = k; l > 1; l--){ cout << trace[cur][l] << " "; cur = trace[cur][l]; } }

Compilation message (stderr)

sequence.cpp:5: warning: ignoring #pragma GCC optimization [-Wunknown-pragmas]
    5 | #pragma GCC optimization ("unroll-loops, no-stack-protector")
      | 
sequence.cpp:34: warning: ignoring #pragma 03  [-Wunknown-pragmas]
   34 | #pragma 03
      |
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...