P3628 [APIO2010] 特别行动队
斜率优化板子题。具体式子不说了QAQ。
记住当让 \(\frac{y_1 - y_2}{x_1 - x_2} \ge k\) 时维护上凸壳,当 \(\frac{y_1 - y_2}{x_1 - x_2} \leq k\) 时维护下凸壳。
还有当化简 \(dp\) 式子的时候,把纯常量提出来,只存纯变量,将与变量相乘的常量作为 \(k\)。
开心
#include <bits/stdc++.h>
typedef long long ll;
int N;
ll a, b, c;
ll value[1010000];
ll dp[1001000], sum[1001000];
// ll queue[1001000], l = 1, r = 0;
ll GetValue(ll val) {
return a * val * val + b * val + c;
}
double Slope(std::pair<ll, ll> &a, std::pair<ll, ll> &b) {
return 1.0 * (b.second - a.second) / (1.0 * (b.first - a.first));
}
class Monotonic_Queue {
public:
std::pair<ll, ll> number[1001000];
int id[1001000];
int l, r;
Monotonic_Queue() {
l = 1, r = 0;
}
bool less(std::pair<ll, ll> &a, std::pair<ll, ll> &b, std::pair<ll, ll> &c) {
return Slope(a, b) <= Slope(b, c);
}
bool greater(std::pair<ll, ll> &a, std::pair<ll, ll> &b, std::pair<ll, ll> &c) {
return Slope(a, b) >= Slope(b, c);
}
void pop(double k) {
while (l + 1 <= r && k < Slope(number[l], number[l + 1]))
l ++;
}
void emplace(ll x, ll y, int ID) {
std::pair<ll, ll> New = std::make_pair(x, y);
while (l + 1 <= r && less(number[r - 1], number[r], New))
r --;
id[++ r] = ID;
number[r] = New;
}
std::pair<ll, ll> front_pos() {
return number[l];
}
int front_id() {
return id[l];
}
}queue;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
std::cin >> N;
std::cin >> a >> b >> c;
for (int i = 1; i <= N; ++ i) {
std::cin >> value[i];
sum[i] = sum[i - 1] + value[i];
}
queue.emplace(0, 0, 0);
for (int i = 1; i <= N; ++ i) {
double k = 2 * a * sum[i];
queue.pop(k);
int j = queue.front_id();
std::pair<ll, ll> temp = queue.front_pos();
dp[i] = temp.second - 2ll * a * sum[i] * sum[j] + 1ll * a * sum[i] * sum[i] + 1ll * b * sum[i] + c;
queue.emplace(sum[i], dp[i] + 1ll * a * sum[i] * sum[i] - 1ll * b * sum[i], i);
}
std::cout << dp[N] << '\n';
return 0;
}
省选联测6 耀眼
逆天根号分治。
不会讲,太菜了QAQ。
伤心
// ubsan: undefined
// accoders
#include <bits/stdc++.h>
typedef long long ll;
const ll mod = 998244353;
const int blocks = 650;
const int S = 1023;
ll N, W;
int dp1[S + 10][1400], dp2[2][400100];
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
#ifndef LOCAL_STDIO
freopen("dazzling.in", "r", stdin);
freopen("dazzling.out", "w", stdout);
#endif
std::cin >> N >> W;
if (N == 1) {
std::cout << 0 << '\n';
return 0;
}
for (int i = 1; i <= N; ++i) {
memset(dp1[i & S], 0, sizeof(dp1[i & S]));
if (i <= blocks)
dp1[i][i] = 1;
for (int j = 1; j <= 1000 && j <= i; ++j)
dp1[i & S][j] = (dp1[i & S][j] + W * dp1[(i - j) & S][j + 1] + dp1[(i - j) & S][j - 1]) % mod;
}
ll answer = 0;
for (int i = 1; i <= 1000; ++i)
answer = (answer + dp1[N & S][i]);
dp2[0][N] = 1;
bool flag = 1;
// answer = 0;
for (int i = 1; i * blocks <= 2 * N; ++i) {
memset(dp2[flag], 0, sizeof(int) * (N * 2));
for (int j = 0; j <= 2 * N; ++j) {
dp2[flag][j] = (dp2[flag][j] + W * (i + j <= 2 * N ? dp2[flag ^ 1][j + i] : 0) + (j - i >= 0 ? dp2[flag ^ 1][j - i] : 0)) % mod;
//注意从flag转移过来的
}
for (int j = blocks + 1; j <= N; ++j)
if (i * j <= 2 * N)
answer = (answer + dp2[flag ^ 1][N * 2 - i * j]);
//这里加 dp2[flag ^ 1] 的原因是:在当前这一位之后,剩下还要选的长度是flag^1滚之前的代表长度
flag ^= 1;
}
answer %= mod;
std::cout << answer << '\n';
return 0;
}
/*
5 2
*/