题单链接
https://vjudge.net/article/752
推荐:1,2,5
1. HDU-3507 Print Article
f i = min 0 ≤ j < i { f j + ( s i − s j ) 2 + M } f_i = \min_{0 \le j < i} \{ f_j + (s_i - s_j)^2 + M \} fi=0≤j<imin{fj+(si−sj)2+M}
// https://vjudge.net/problem/HDU-3507
#include <cstdio>
using namespace std;
/*
fi = min{ fj + (si-sj)^2 + m }
k<j<i
j better than k
fk + (si-sk)^2 + m > fj + (si-sj)^2 + m
fk + sk^2 - 2*si*sk > fj + sj^2 - 2*si*sj
sj^2 - sk^2 + fj - fk < si*2*(sj-sk)
((sj^2+fj)-(sk^2+fj)) / (2*sj - 2*sk) < si
xi = 2*si
yi = si^2 + fi
*/
#define MAXN 500005
int n, m;
long long c[MAXN];
long long s[MAXN];
long long x[MAXN], y[MAXN];
long long f[MAXN];
int q[MAXN], ql, qr;
bool solve()
{
if (scanf("%d%d", &n, &m)!=2) return false;
for (int i=1; i<=n; i++) {
scanf("%lld", &c[i]);
s[i] = s[i-1]+c[i];
}
ql=1;
qr=0;
q[++qr] = 0;
for (int i=1; i<=n; i++) {
while (ql<qr && (y[q[ql+1]] - y[q[ql]]) <= s[i]*(x[q[ql+1]] - x[q[ql]])) // 注意要加上等于号
ql++;
f[i] = f[q[ql]] + (s[i] - s[q[ql]])*(s[i] - s[q[ql]]) + m;
x[i] = 2*s[i];
y[i] = s[i]*s[i] + f[i];
while (ql<qr && ((y[i] - y[q[qr]])*(x[q[qr]]-x[q[qr-1]]) <= (y[q[qr]]-y[q[qr-1]])*(x[i]-x[q[qr]])))
qr--;
q[++qr] = i;
}
printf("%lld\n", f[n]);
return true;
}
int main()
{
while (solve());
return 0;
}
/*
5 5
5 9 5 7 5
*/
2. HDU-2829 Lawrence
f m , i = min m < j < i { f j + ( s i − s j ) 2 − ( t i − t j ) 2 } f_{m,i} = \min_{m < j < i} \{ f_j + \frac{(s_i - s_j)^2 - (t_i - t_j)}{2} \} fm,i=m<j<imin{fj+2(si−sj)2−(ti−tj)}
#include <cstdio>
/*
s[k] = Sum[ai, {i, 1, k}]
t[k] = Sum[ai^2, {i, 1, k}]
fi = min{ fj + ((si-sj)^2 - (ti-tj)) / 2 }
k<j
j better than k
fj + ((si-sj)^2 - (ti-tj))/2 < fk + ((si-sk)^2 - (ti-tk))/2
((2fj + sj^2 + tj) - (2fk + sk^2 + tk)) / (2sj - 2sk) < si
yi = 2fi + si^2 + ti
xi = 2si
(k, j) < (j, i)
*/
#define MAXN 1000
int n, m;
long long s[MAXN];
long long t[MAXN];
long long dp[MAXN][MAXN]; // ans = dp[m+1][n]
int q[MAXN], ql, qr;
long long get_up(int k, int j, long long *f)
{
return (2*f[j] + s[j]*s[j] + t[j]) - (2*f[k] + s[k]*s[k] + t[k]);
}
long long get_down(int k, int j)
{
return ((s[j]-s[k])<<1);
}
bool solve()
{
int tmp;
scanf("%d%d", &n, &m);
if ((n|m) == 0) return false;
for (int i=1; i<=n; i++) {
scanf("%d", &tmp);
s[i] = s[i-1] + tmp;
t[i] = t[i-1] + tmp*tmp;
}
for (int i=1; i<=n; i++) {
dp[1][i] = (s[i]*s[i]-t[i])/2;
}
for (int mm=2, maxmm=m+1; mm<=maxmm; mm++) {
ql = 1;
qr = 0;
q[++qr] = mm-1; // 注意前面至少有 mm-1 个,所以一开始入队列的是 mm-1
for (int i=mm; i<=n; i++) {
while (ql<qr && get_up(q[ql], q[ql+1], dp[mm-1]) <= get_down(q[ql], q[ql+1])*s[i])
ql++;
dp[mm][i] = dp[mm-1][q[ql]] + ((s[i]-s[q[ql]])*(s[i]-s[q[ql]]) - (t[i]-t[q[ql]]))/2;
while (ql<qr && get_up(q[qr-1], q[qr], dp[mm-1])*get_down(q[qr], i) >= get_up(q[qr], i, dp[mm-1])*get_down(q[qr-1], q[qr]))
qr--;
q[++qr] = i;
}
}
printf("%lld\n", dp[m+1][n]);
return true;
}
int main()
{
while (solve());
return 0;
}
/*
4 1
4 5 1 2
4 2
4 5 1 2
0 0
17 2
20 5
23 95 77 90 77 69 24 84 73 9 37 11 28 33 42 39 64 18 91 6
49824
7 3
65 63 99 3 31 16 84
4732
10 6
63 97 45 93 42 82 94 8 40 9
4196
10 8
37 71 3 16 74 91 5 40 40 49
48
5 3
5 4 3 2 1
*/
4. HDU-1300 Pearls
f i = min 0 ≤ j < i { f j + ( s i − s j + 10 ) ∗ p i } f_i = \min_{0 \le j < i} \{ f_j + (s_i - s_j + 10)*p_i \} fi=0≤j<imin{fj+(si−sj+10)∗pi}
#include <cstdio>
/*
p[i] < p[i+1]
si = a1+a2+...+ai
fi = min{ fj + (si-sj+10)*mxp[j+1..i] }
fi = min{ fj + (si-sj+10)*p[i]}
k<j<i
j better than k
fj + (si-sj+10)*pi < fk + (si-sk+10)*pi
fj-sj*p[i] < fk-sk*p[i]
(fj-fk)/(sj-sk) < pi
yi = fi
xi = si
(k, j) < (j, i)
*/
#define MAXN 200
int n;
long long a[MAXN];
long long p[MAXN];
long long s[MAXN];
long long f[MAXN];
long long q[MAXN], ql, qr;
long long get_up(int k, int j)
{
return f[j]-f[k];
}
long long get_down(int k, int j)
{
return s[j]-s[k];
}
void solve()
{
scanf("%d", &n);
for (int i=1; i<=n; i++) {
scanf("%lld%lld", &a[i], &p[i]);
s[i] = s[i-1]+a[i];
}
ql=1;
qr=0;
q[++qr] = 0;
for (int i=1; i<=n; i++) {
while (ql<qr && get_up(q[ql], q[ql+1]) <= p[i] * get_down(q[ql], q[ql+1]))
ql++;
f[i] = f[q[ql]] + (s[i]-s[q[ql]]+10)*p[i];
while (ql<qr && get_up(q[qr-1], q[qr])*get_down(q[qr], i) >= get_up(q[qr], i)*get_down(q[qr-1], q[qr]))
qr--;
q[++qr] = i;
}
printf("%lld\n", f[n]);
}
int main()
{
int ttt;
scanf("%d", &ttt);
while (ttt--) {
solve();
}
return 0;
}
/*
2
100 1
100 2
330
3
1 10
1 11
100 12
1344
5
6 3
4 3
4 5
9 9
8 9
339
*/
5. HDU-2993 MAX Average Problem
这题卡读入优化有点骚
这题是纯斜率的,和前面几题有点不同,不过也没有差太多。可以说是另一类板子题吧。
https://blog.csdn.net/qq_36294918/article/details/103641411
f
i
=
max
0
≤
j
≤
i
−
k
{
s
i
−
s
j
i
−
j
}
f_i = \max_{0 \le j \le i-k} \{ \frac{s_i - s_j}{i - j} \}
fi=0≤j≤i−kmax{i−jsi−sj}
#include <cstdio>
/*
fi = max{ (si-sj)/(i-j) , 0<=j<=i-k }
k<j<i
j better than k
(si-sj)/(i-j) > (si-sk)/(i-k)
(si-sj)*(i-k) > (si-sk)*(i-j)
*/
#define MAXN 100005
int n, m;
int a[MAXN];
int s[MAXN];
int f[MAXN];
int q[MAXN], ql, qr;
double ans;
inline char __getchar()
{
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline bool qread(int &x)
{
char ch=__getchar();
if(ch==EOF)return false;
x=0;
while(!(ch>='0'&&ch<='9'))ch=__getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=__getchar();
return x;
}
double max(const double &x, const double &y) {return x<y?y:x;}
double get_k(int x, int y) {return 1.0*(s[y]-s[x])/(y-x);}
int solve()
{
if (!qread(n) || !qread(m)) return false;
for (int i=1; i<=n; i++) qread(a[i]), s[i] = s[i-1]+a[i];
ql=1;
qr=0;
ans=0;
for (int i=m, ii=0; i<=n; i++, ii++) {
while (ql<qr && get_k(q[qr-1], q[qr])>=get_k(q[qr], ii))
qr--;
q[++qr] = ii;
while (ql<qr && get_k(q[ql], i)<=get_k(q[ql+1], i))
ql++;
ans = max(ans, get_k(q[ql], i));
}
printf("%.2f\n", ans);
return true;
}
int main()
{
while (solve());
return 0;
}
/*
10 6
6 4 2 10 3 8 5 9 4 1
6.50
*/