【刷题记录】[AtCoder Educational DP Contest] 经典dp类型及方法题解合集

文章目录

  • A - Frog 1
  • B - Frog 2
  • C - Vacation
  • D - Knapsack 1
  • E - Knapsack 2
  • F - LCS
  • G - Longest Path
  • H - Grid 1
  • I - Coins
  • J - Sushi
  • K - Stones
  • L - Deque
  • M - Candies
  • N - Slimes
  • O - Matching
  • P - Independent Set
  • Q - Flowers
  • R - Walk
  • S - Digit Sum
  • T - Permutation
  • U - Grouping
  • V - Subtree
  • W - Intervals
  • X - Tower
  • Y - Grid 2
  • Z - Frog 3

Atcoder

A - Frog 1

luogu

f(i):f(i):f(i): 青蛙在 iii 石头的最小费用。

只有两种跳法,暴力枚举转移即可,O(n)O(n)O(n)

f(i+1)←min⁡f(i)+∣hi−hi+1∣f(i+1)\leftarrow^{\min} f(i)+|h_i-h_{i+1}|f(i+1)minf(i)+hihi+1

f(i+2)←min⁡f(i)+∣hi−hi+2∣f(i+2)\leftarrow^{\min} f(i)+|h_i-h_{i+2}|f(i+2)minf(i)+hihi+2

#include <bits/stdc++.h>
using namespace std;
#define maxn 100005
int n;
int h[maxn], f[maxn];
int Fabs( int x ) { return x < 0 ? -x : x; }
int main() {scanf( "%d", &n );for( int i = 1;i <= n;i ++ ) scanf( "%d", &h[i] );memset( f, 0x3f, sizeof( f ) );f[1] = 0;for( int i = 1;i < n;i ++ ) {f[i + 1] = min( f[i + 1], f[i] + Fabs( h[i] - h[i + 1] ) );f[i + 2] = min( f[i + 2], f[i] + Fabs( h[i] - h[i + 2] ) );}printf( "%d\n", f[n] );return 0;
}

B - Frog 2

luogu

青蛙可以跳的步数变大了,但仍可以直接枚举跳的步数 jjj

f(i):f(i):f(i): 青蛙在石头 iii 上的最小花费。

f(i+j)←min⁡f(i)+∣hi−hi+j∣,1≤j≤kf(i+j)\leftarrow^{\min} f(i)+|h_i-h_{i+j}|,1\le j\le kf(i+j)minf(i)+hihi+j,1jk

时间复杂度 O(nk)O(nk)O(nk)

#include <bits/stdc++.h>
using namespace std;
#define maxn 100005
int n, k;
int h[maxn], f[maxn];
int Fabs( int x ) { return x < 0 ? -x : x; }
int main() {scanf( "%d %d", &n, &k );for( int i = 1;i <= n;i ++ ) scanf( "%d", &h[i] );memset( f, 0x3f, sizeof( f ) );f[1] = 0;for( int i = 1;i < n;i ++ )for( int j = 1;j <= k;j ++ )if( i + j <= n )f[i + j] = min( f[i + j], f[i] + Fabs( h[i] - h[i + j] ) );printf( "%d\n", f[n] );return 0;
}

C - Vacation

luogu

f(i,0/1/2):f(i,0/1/2):f(i,0/1/2):iii 天,太朗游泳/捉虫/写作业的最大幸福值。

枚举前一天的状态,相邻两天不同即可。

k≠j∧f(i−1,k)→f(i,j)k\ne j\wedge f(i-1,k)\rightarrow f(i,j)k=jf(i1,k)f(i,j)

时间复杂度 O(9n)O(9n)O(9n)

#include <bits/stdc++.h>
using namespace std;
#define maxn 100005
int n;
int v[maxn][3], f[maxn][3];
int main() {scanf( "%d", &n );for( int i = 1;i <= n;i ++ )for( int j = 0;j < 3;j ++ )scanf( "%d", &v[i][j] );for( int i = 1;i <= n;i ++ )for( int j = 0;j < 3;j ++ )for( int k = 0;k < 3;k ++ )if( j == k ) continue;else f[i][j] = max( f[i][j], f[i - 1][k] + v[i][j] );printf( "%d\n", max( f[n][0], max( f[n][1], f[n][2] ) ) );return 0;
}

D - Knapsack 1

luogu

010101 背包问题板题。

#include <bits/stdc++.h>
using namespace std;
#define int long long
int n, m;
int w[105], v[105];
int f[100005];signed main() {scanf( "%lld %lld", &n, &m );for( int i = 1;i <= n;i ++ ) scanf( "%ld %lld", &w[i], &v[i] );for( int i = 1;i <= n;i ++ )for( int j = m;j >= w[i];j -- )f[j] = max( f[j], f[j - w[i]] + v[i] );int ans = 0;for( int i = m;i;i -- ) ans = max( ans, f[i] );printf( "%lld\n", ans );return 0;
}

E - Knapsack 2

010101 背包问题板题。

上一题是总重量可以用数组开下,这一题不行,但我们发现价值总和不超过 1e51e51e5

所以 f(i,j):f(i,j):f(i,j): 考虑前 iii 个物品,总价值为 jjj 的最小重量。

#include <bits/stdc++.h>
using namespace std;
#define int long long
int n, m;
int w[105], v[105];
int f[100005];signed main() {scanf( "%lld %lld", &n, &m );for( int i = 1;i <= n;i ++ ) scanf( "%ld %lld", &w[i], &v[i] );memset( f, 0x3f, sizeof( f ) );f[0] = 0;for( int i = 1;i <= n;i ++ )for( int j = 1e5;j >= v[i];j -- )f[j] = min( f[j], f[j - v[i]] + w[i] );for( int i = 1e5;~ i;i -- )if( f[i] <= m ) return ! printf( "%lld\n", i );return 0;
}

F - LCS

luogu

f(i,j):f(i,j):f(i,j): sss 串前 iii 个字母和 ttt 串前 jjj 个字母的最长公共子序列。

f(i,j)=max⁡{f(i−1,j),f(i,j−1)}f(i,j)=\max\{f(i-1,j),f(i,j-1)\}f(i,j)=max{f(i1,j),f(i,j1)}

如果 si=tjs_i=t_jsi=tj 则还有一种转移:f(i,j)←f(i−1,j−1)+1f(i,j)\leftarrow f(i-1,j-1)+1f(i,j)f(i1,j1)+1

输出方案就直接从 (n,m)(n,m)(n,m) 开始往前找 fff 相同或者 sn=tms_n=t_msn=tm 时相差为 111,递归输出。

时间复杂度: O(n2)O(n^2)O(n2)

#include <bits/stdc++.h>
using namespace std;
#define maxn 3005
int f[maxn][maxn], g[maxn][maxn];
char s[maxn], t[maxn];
int n, m;void print( int x, int y ) {if( ! x or ! y ) return;if( f[x][y] == f[x - 1][y - 1] + 1 and s[x] == t[y] ) {print( x - 1, y - 1 );printf( "%c", s[x] );}else if( f[x][y] == f[x - 1][y] ) print( x - 1, y );else print( x, y - 1 );
}int main() {scanf( "%s %s", s + 1, t + 1 );int n = strlen( s + 1 );int m = strlen( t + 1 );for( int i = 1;i <= n;i ++ )for( int j = 1;j <= m;j ++ ) {if( s[i] == t[j] ) f[i][j] = max( f[i - 1][j - 1] + 1, f[i][j] );f[i][j] = max( f[i][j], f[i - 1][j] );f[i][j] = max( f[i][j], f[i][j - 1] );}print( n, m );return 0;
}

G - Longest Path

luogu

有向无环图。直接拓扑序上 dpdpdp 即可。设 f(i):f(i):f(i):iii 的最长路径。时间复杂度 O(n)O(n)O(n)

#include <bits/stdc++.h>
using namespace std;
#define maxn 100005
int n, m;
int d[maxn], f[maxn];
vector < int > G[maxn];
queue < int > q;int main() {scanf( "%d %d", &n, &m );for( int i = 1, x, y;i <= m;i ++ ) {scanf( "%d %d", &x, &y );G[x].push_back( y );d[y] ++;}int ans = 0;for( int i = 1;i <= n;i ++ )if( ! d[i] ) q.push( i );while( ! q.empty() ) {int u = q.front(); q.pop();ans = max( ans, f[u] );for( int v : G[u] ) {f[v] = max( f[v], f[u] + 1 );if( ! --d[v] ) q.push( v );}}	printf( "%d\n", ans );return 0;
}

H - Grid 1

luogu

f(i,j):f(i,j):f(i,j):(i,j)(i,j)(i,j) 位置的方案数。

如果该位置不是障碍,就有转移 f(i,j)=f(i−1,j)+f(i,j−1)f(i,j)=f(i-1,j)+f(i,j-1)f(i,j)=f(i1,j)+f(i,j1)

时间复杂度 O(n2)O(n^2)O(n2)

#include <bits/stdc++.h>
using namespace std;
#define maxn 1005
#define int long long
#define mod 1000000007
char ch[maxn][maxn];
int f[maxn][maxn];
int n, m;signed main() {scanf( "%lld %lld", &n, &m );for( int i = 1;i <= n;i ++ ) scanf( "%s", ch[i] + 1 );f[1][1] = 1;for( int i = 1;i <= n;i ++ )for( int j = 1;j <= m;j ++ )if( (i ^ 1 or j ^ 1) and ch[i][j] == '.' )f[i][j] = ( f[i][j - 1] + f[i - 1][j] ) % mod;printf( "%lld\n", f[n][m] );return 0;
}

I - Coins

luogu

f(i,j):f(i,j):f(i,j): 到第 iii 次翻硬币为止,正面朝上的次数为 jjj 的概率。

f(i+1,j+1)←f(i,j)∗pif(i+1,j+1)\leftarrow f(i,j)*p_if(i+1,j+1)f(i,j)pif(i+1,j)←f(i,j)∗(1−pi)f(i+1,j)\leftarrow f(i,j)*(1-p_i)f(i+1,j)f(i,j)(1pi)

还有一种设 f(i,j):f(i,j):f(i,j): 到第 iii 次翻硬币为止,增面朝上的次数比反面朝上的次数多 jjj 次的概率。

jjj 就有可能是负数,就需要整体状态右移为非负数。难写典型的吃力不讨好。

这种把差值当成一维来写,多半是需要优化时空时才考虑的。

#include <bits/stdc++.h>
using namespace std;
#define maxn 6005
int n;
double p[maxn];
double f[maxn][maxn];int main() {scanf( "%d", &n );for( int i = 1;i <= n;i ++ ) scanf( "%lf", &p[i] );f[0][0] = 1;for( int i = 1;i <= n;i ++ ) {f[i][0] = f[i - 1][0] * (1 - p[i]);for( int j = 1;j <= i;j ++ )f[i][j] = f[i - 1][j - 1] * p[i] + f[i - 1][j] * (1 - p[i]);}double ans = 0;for( int i = 0;i <= n;i ++ ) if( i > n - i ) ans += f[n][i];printf( "%.10f\n", ans );return 0;
}

J - Sushi

题解链接

K - Stones

SG\text{SG}SG 函数简单应用。

直接记忆化搜索 f(i):f(i):f(i): 剩下石子数为 iii 时当前操作的先手必胜 111 还是必败 000

如果所有后继状态都是必胜态,则该状态必败;否则必胜。

#include <bits/stdc++.h>
using namespace std;
int n, k;
int a[105], f[100005];int dfs( int x ) {if( x < a[1] ) return f[x] = 0;if( ~ f[x] ) return f[x];f[x] = 0;for( int i = 1;i <= n;i ++ ) {if( x < a[i] ) continue;if( ! dfs( x - a[i] ) ) f[x] = 1;	}return f[x];
}int main() {memset( f, -1, sizeof( f ) );scanf( "%d %d", &n, &k );for( int i = 1;i <= n;i ++ ) scanf( "%d", &a[i] );if( dfs( k ) ) puts("First");else puts("Second");return 0;
}

L - Deque

luogu

显然区间 dpdpdp

f(i,j):f(i,j):f(i,j): 只剩区间 [i,j][i,j][i,j] 中的数,当前先手按最优策略行动的 X−YX-YXY

因为两人都只能从首尾取数,所以剩下来的一定是一段连续区间,就没有枚举 [i,j][i,j][i,j] 中的断点 kkk 操作。

取了奇数个就是后手操作,减去取 min⁡\minmin;否则是先手操作,加上取 max⁡\maxmax

f(i,j)=max⁡/min⁡{f(i+1,j)±ai,f(i,j−1)±ai}f(i,j)=\max/\min\{f(i+1,j)±a_i,f(i,j-1)±a_i\}f(i,j)=max/min{f(i+1,j)±ai,f(i,j1)±ai}

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define maxn 3005
int n;
int a[maxn];
int f[maxn][maxn];
signed main() {scanf( "%lld", &n );for( int i = 1;i <= n;i ++ ) scanf( "%lld", &a[i] );for( int len = 1;len <= n;len ++ )for( int i = 1;i <= n;i ++ ) {int j = i + len - 1;if( j > n ) break;if( (n - len) & 1 ) f[i][j] = min( f[i + 1][j] - a[i], f[i][j - 1] - a[j] );else f[i][j] = max( f[i + 1][j] + a[i], f[i][j - 1] + a[j] );}printf( "%lld\n", f[1][n] );return 0;
}

M - Candies

luogu

f(i,j):f(i,j):f(i,j): 到第 iii 个小朋友为止,一共分了 jjj 颗糖的方案数。

枚举第 iii 个小朋友分的糖数 kkk

f(i,j)=∑k=0aif(i−1,j−k)f(i,j)=\sum_{k=0}^{a_i}f(i-1,j-k)f(i,j)=k=0aif(i1,jk)

前缀和优化,O(nk)O(nk)O(nk)

g(i,j)=∑k=0jf(i,j),f(i,j)=gi−1,j−gi−1,j−ai−1g(i,j)=\sum_{k=0}^jf(i,j),f(i,j)=g_{i-1,j}-g_{i-1,j-a_i-1}g(i,j)=k=0jf(i,j),f(i,j)=gi1,jgi1,jai1

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define mod 1000000007
int f[105][100005];
int n, k;
int a[105];
signed main() {scanf( "%lld %lld", &n, &k );for( int i = 1;i <= n;i ++ ) scanf( "%lld", &a[i] );for( int i = 0;i <= k;i ++ ) f[0][i] = 1;for( int i = 1;i <= n;i ++ ) {for( int j = 0;j <= k;j ++ )if( j >= a[i] + 1 ) f[i][j] = ( f[i - 1][j] - f[i - 1][j - a[i] - 1] ) % mod;else f[i][j] = f[i - 1][j];if( i ^ n ) for( int j = 1;j <= k;j ++ ) (f[i][j] += f[i][j - 1]) %= mod;}printf( "%lld\n", (f[n][k] + mod) % mod );return 0;
}

N - Slimes

luogu

每次是选相邻两个数合并,显然区间 dpdpdp 枚举断点类型。

f(i,j):f(i,j):f(i,j): 合并区间 [i,j][i,j][i,j] 的最小代价。

枚举 i≤k<j,f(i,j)←min⁡f(i,k)+f(k+1,j)+w[i,j]i\le k<j,f(i,j)\leftarrow\min f(i,k)+f(k+1,j)+w[i,j]ik<j,f(i,j)minf(i,k)+f(k+1,j)+w[i,j]

其中 w[i,j]=∑k=ijakw[i,j]=\sum_{k=i}^ja_kw[i,j]=k=ijak,即 aaa 的前缀和。

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define maxn 405
int n;
int a[maxn], g[maxn];
int f[maxn][maxn];signed main() {scanf( "%lld", &n );for( int i = 1;i <= n;i ++ ) scanf( "%lld", &a[i] );for( int i = 1;i <= n;i ++ ) g[i] = g[i - 1] + a[i];memset( f, 0x3f, sizeof( f ) );for( int i = 1;i <= n;i ++ ) f[i][i] = 0;for( int len = 1;len <= n;len ++ )for( int i = 1;i <= n;i ++ ) {int j = i + len - 1;if( j > n ) break;for( int k = i;k < j;k ++ )f[i][j] = min( f[i][j], f[i][k] + f[k + 1][j] + g[j] - g[i - 1] );}printf( "%lld\n", f[1][n] );return 0;
}

O - Matching

luogu

状压 dpdpdp 即可。

f(s,i):f(s,i):f(s,i): 考虑到第一个集合的第 iii 个点的匹配,前面点在第二个集合的匹配点集为 sss 的方案数。

直接枚举不在 sss 中的第二个集合的点 jjj,若 i,ji,ji,j 可以匹配,则转移即可。

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define mod 1000000007
#define maxn 21
int f[1 << maxn][maxn];
int g[maxn][maxn];
int n;
signed main() {scanf( "%lld", &n );for( int i = 0;i < n;i ++ )for( int j = 0;j < n;j ++ )scanf( "%lld", &g[i][j] );f[0][0] = 1;for( int i = 0;i < n;i ++ ) {for( int s = 0;s < (1 << n);s ++ ) {if( __builtin_popcount( s ) ^ i ) continue;for( int j = 0;j < n;j ++ )if( (s >> j & 1) or ! g[i][j] ) continue;else (f[s | (1 << j)][i + 1] += f[s][i]) %= mod;}}printf( "%lld\n", f[(1 << n) - 1][n] );return 0;
}

P - Independent Set

luogu

树形 dpdpdp

f(u,0/1):f(u,0/1):f(u,0/1):uuu 染成白/黑色且子树内染色均合法的方案数。

f(u,0)∗=(f(v,1)+f(v,0));f(u,1)∗=f(v,0)f(u,0)*=(f(v,1)+f(v,0));f(u,1)*=f(v,0)f(u,0)=(f(v,1)+f(v,0));f(u,1)=f(v,0)

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define mod 1000000007
#define maxn 100005
int n;
vector < int > G[maxn];
int f[maxn][2];
void dfs( int u, int fa ) {f[u][0] = f[u][1] = 1;for( int v : G[u] ) {if( v == fa ) continue;else dfs( v, u );f[u][0] = f[u][0] * (f[v][1] + f[v][0]) % mod;f[u][1] = f[u][1] * f[v][0] % mod;}
}
signed main() {scanf( "%lld", &n );for( int i = 1, u, v;i < n;i ++ ) {scanf( "%lld %lld", &u, &v );G[u].push_back( v );G[v].push_back( u );}dfs( 1, 0 );printf( "%lld\n", (f[1][0] + f[1][1]) % mod );return 0;
}

Q - Flowers

luogu

线段树优化 dpdpdp 转移。

f(i):f(i):f(i):iii 朵花必须留下的最大权值和。

枚举上一朵留下的花 jjj ,则 f(i)=max⁡j<i∧hj<hi{f(j)+ai}f(i)=\max_{j<i\wedge h_j<h_i}\{f(j)+a_i\}f(i)=maxj<ihj<hi{f(j)+ai}

hhh 当作线段树下标建树,fff 做权值,则合法的 jjj 对应树上的一段区间。

只需要维护区间查询最大值以及单点修改即可。

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define maxn 200005
int n, ans;
int h[maxn], a[maxn], f[maxn], t[maxn << 2];
#define lson now << 1
#define rson now << 1 | 1
#define mid  (l + r >> 1)
void modify( int now, int l, int r, int p, int v ) {if( l == r ) { t[now] = v; return; }if( p <= mid ) modify( lson, l, mid, p, v );else modify( rson, mid + 1, r, p, v );t[now] = max( t[lson], t[rson] );
}
int query( int now, int l, int r, int L, int R ) {if( R < l or r < L ) return 0;if( L <= l and r <= R ) return t[now];return max(query( lson, l, mid, L, R ), query( rson, mid + 1, r, L, R ));
}
signed main() {scanf( "%lld", &n );for( int i = 1;i <= n;i ++ ) scanf( "%lld", &h[i] );for( int i = 1;i <= n;i ++ ) scanf( "%lld", &a[i] );for( int i = 1;i <= n;i ++ ) {f[i] = query( 1, 1, n, 1, h[i] ) + a[i];modify( 1, 1, n, h[i], f[i] );ans = max( ans, f[i] );}printf( "%lld\n", ans );return 0;
}

R - Walk

luogu

f(i,j):f(i,j):f(i,j):iii 步后在 jjj 点的方案数。

转移则是枚举能到达 jjj 点的所有点 kkkf(i,j)=∑g(k,j)=1f(i−1,k)f(i,j)=\sum_{g(k,j)=1} f(i-1,k)f(i,j)=g(k,j)=1f(i1,k)

转移的 ggg 是固定不变的,所以步数可以矩阵加速。

#include <bits/stdc++.h>
using namespace std;
#define maxn 52
#define int long long
#define mod 1000000007
int n, k;
struct matrix {int c[maxn][maxn];matrix(){ memset( c, 0, sizeof( c ) ); }matrix operator * ( matrix &v ) {matrix ans;for( int i = 1;i <= n;i ++ )for( int k = 1;k <= n;k ++ )for( int j = 1;j <= n;j ++ )(ans.c[i][j] += c[i][k] * v.c[k][j]) %= mod;return ans;}
}f, g;
matrix qkpow( matrix x, int y ) {matrix ans;for( int i = 1;i <= n;i ++ ) ans.c[i][i] = 1;while( y ) {if( y & 1 ) ans = ans * x;x = x * x;y >>= 1;}return ans;
}
signed main() {scanf( "%lld %lld", &n, &k );for( int i = 1;i <= n;i ++ )for( int j = 1;j <= n;j ++ )scanf( "%lld", &g.c[i][j] );g = qkpow( g, k );for( int i = 1;i <= n;i ++ ) f.c[1][i] = 1;f = f * g;int ans = 0;for( int i = 1;i <= n;i ++ ) (ans += f.c[1][i]) %= mod;printf( "%lld\n", ans );return 0;
}

S - Digit Sum

数位 dpdpdp

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define mod 1000000007
int f[10005][105];
int n, m;
char s[10005]; 
int num[10005];
int dfs( int x, int sum, bool lim ) {if( ! lim and ~ f[x][sum] ) return f[x][sum];if( ! x ) return sum == 0;int up = lim ? num[x] : 9;int ans = 0;for( int i = 0;i <= up;i ++ ) {ans += dfs( x - 1, (sum + i) % m, lim & (i == up) );ans %= mod;}if( ! lim ) f[x][sum] = ans;return ans;
}
signed main() {scanf( "%s %lld", s + 1, &m );n = strlen( s + 1 );reverse( s + 1, s + n + 1 );for( int i = 1;i <= n;i ++ ) num[i] = s[i] ^ 48;memset( f, -1, sizeof( f ) );printf( "%lld\n", (mod - 1 + dfs( n, 0, 1 )) % mod );return 0;
}

T - Permutation

题解链接

U - Grouping

状压 dpdpdp

预处理 g(s):g(s):g(s): sss 集合内的物品分成一个集合的得分之和。

f(s):f(s):f(s): 若干个分组的集合为 sss 的最大得分之和。

枚举最新加入的分组集合 ttt 即可,子集枚举 O(3n)O(3^n)O(3n)

f(s)=max⁡t⊂s{f(s⊕t)+g(t)}f(s)=\max_{t\subset s}\{f(s\oplus t)+g(t)\}f(s)=maxts{f(st)+g(t)}

#include <bits/stdc++.h>
using namespace std;
#define maxn 17
#define int long long
int g[1 << maxn];
int f[1 << maxn];
int a[maxn][maxn];
int n;
signed main() {scanf( "%lld", &n );for( int i = 0;i < n;i ++ )for( int j = 0;j < n;j ++ )scanf( "%lld", &a[i][j] );for( int s = 0;s < (1 << n);s ++ )for( int i = 0;i < n;i ++ )for( int j = i + 1;j < n;j ++ )if( (s >> i & 1) and (s >> j & 1) )g[s] += a[i][j];f[0] = 0;for( int s = 1;s < (1 << n);s ++ ) {int ans = -1e18;for( int t = s;t;t = (t - 1) & s )ans = max( ans, f[s ^ t] + g[t] );f[s] = ans;}printf( "%lld\n", f[(1 << n) - 1] );return 0;
}

V - Subtree

题解链接

W - Intervals

题解链接

X - Tower

题解链接

Y - Grid 2

题解链接

Z - Frog 3

luogu

f(i):f(i):f(i): 青蛙在 iii 石头上的最小花费。

f(i)=min⁡{f(j)+(hi−hj)2+C}=min⁡{−2hj∗hi+f(j)+C}+hi∗hi+Cf(i)=\min\{f(j)+(h_i-h_j)^2+C\}=\min\{-2h_j*h_i+f(j)+C\}+h_i*h_i+Cf(i)=min{f(j)+(hihj)2+C}=min{2hjhi+f(j)+C}+hihi+C

李超树板题,也可斜率优化。

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define maxn 1000005
#define V 1000000
#define lson now << 1
#define rson now << 1 | 1
#define mid  (l + r >> 1)
struct node { int k, b; }t[maxn << 2];
int n, C;
int h[maxn], f[maxn];
void build( int now, int l, int r ) {t[now].k = t[now].b = 1e10;if( l == r ) return;build( lson, l, mid );build( rson, mid + 1, r );
}
int calc( node l, int x ) { return l.k * x + l.b; }
bool cover( node Old, node New, int x ) { return calc( New, x ) <= calc( Old, x ); }
void insert( int now, int l, int r, node New ) {if( cover( t[now], New, l ) and cover( t[now], New, r ) ) { t[now] = New; return; }if( l == r ) return; if( cover( t[now], New, mid ) ) swap( t[now], New );if( cover( t[now], New, l ) ) insert( lson, l, mid, New );if( cover( t[now], New, r ) ) insert( rson, mid + 1, r, New );
}
int query( int now, int l, int r, int x ) {if( t[now].k == 1e10 ) return 1e18; if( l == r ) return calc( t[now], x );if( x <= mid ) return min( query( lson, l, mid, x ), calc( t[now], x ) );else return min( query( rson, mid + 1, r, x ), calc( t[now], x ) ); 
}
signed main() {scanf( "%lld %lld", &n, &C );for( int i = 1;i <= n;i ++ ) scanf( "%lld", &h[i] );build( 1, 1, V );for( int i = 1;i <= n;i ++ ) {if(i > 1) f[i] = query( 1, 1, V, h[i] ) + h[i] * h[i] + C;insert( 1, 1, V, (node){ -2 * h[i], f[i] + h[i] * h[i] } );}printf( "%lld\n", f[n] );return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/316300.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

程序员修神之路--问世间异步为何物?

菜菜哥&#xff0c;今天天气挺热的&#xff0c;我都穿裙子了说吧&#xff0c;什么事&#xff1f;&#xff1f;苦笑一下..... 老大说把所有的接口都改成异步操作异步好呀&#xff0c;最少比同步能提高吞吐量异步是怎么回事呢&#xff0c;能讲讲不&#xff1f;来&#xff0c;凑近…

P3455 [POI2007]ZAP-Queries

P3455 [POI2007]ZAP-Queries 题意&#xff1a; 求满足1≤x≤a,1≤y≤b1\leq x\leq a,1\leq y\leq b1≤x≤a,1≤y≤b&#xff0c;且gcd(x,y)dgcd(x,y)dgcd(x,y)d的二元组(x,y)的数量 题解&#xff1a; 莫比乌斯反演板子 代码&#xff1a; // Problem: P3455 [POI2007]ZAP…

.NET Core 使用MailKit发送电子邮件

点击上方蓝字关注“汪宇杰博客”发送邮件通知的功能在各种系统里都很常见。我的博客也能在有新评论、新回复&#xff0c;或者文章被其他网站引用时向管理员发送邮件。那么在.NET Core里&#xff0c;如何实现发送电子邮件呢&#xff1f;准备工作我的案例会利用微软outlook.com的…

P3327 [SDOI2015]约数个数和

P3327 [SDOI2015]约数个数和 题意&#xff1a; 设 d(x) 为 x 的约数个数&#xff0c;给定 n,m&#xff0c;求 ∑i1n∑j1md(i,j)\sum_{i1}^{n}\sum_{j1}^{m}d(i,j)∑i1n​∑j1m​d(i,j) 题解&#xff1a; 代码&#xff1a; // Problem: P3327 [SDOI2015]约数个数和 // Conte…

[CQOI2018] 解锁屏幕(状压dp)

problem luogu-P4460 solution 题面以及数据告诉我们显然是状压 dpdpdp。 设 f(s,i):f(s,i):f(s,i): 经过的点集 sss 最后一次画的点为 iii 的方案数。 直接枚举下一个之前没被画的点 jjj 转移即可。 f(s∣2j,j)←f(s,i)f(s|2^j,j)\leftarrow f(s,i)f(s∣2j,j)←f(s,i)。 …

C#并行编程(6):线程同步面面观

理解线程同步线程的数据访问在并行&#xff08;多线程&#xff09;环境中&#xff0c;不可避免地会存在多个线程同时访问某个数据的情况。多个线程对共享数据的访问有下面3种情形&#xff1a;多个线程同时读取数据&#xff1b;单个线程更新数据&#xff0c;此时其他线程读取数据…

P2522 [HAOI2011]Problem b

P2522 [HAOI2011]Problem b 题意&#xff1a; 对于给出的 n 个询问&#xff0c;每次求有多少个数对 (x,y)&#xff0c;满足 a≤x≤b&#xff0c;c≤y≤d&#xff0c;且 gcd(x,y)k&#xff0c;gcd(x,y) 函数为 x 和 y 的最大公约数。 题解&#xff1a; 这个题跟P3455 [POI20…

[十二省联考 2019] 异或粽子(可持久化字典树 + 二叉堆)

problem luogu-P5283 小粽是一个喜欢吃粽子的好孩子。今天她在家里自己做起了粽子。 小粽面前有 nnn 种互不相同的粽子馅儿&#xff0c;小粽将它们摆放为了一排&#xff0c;并从左至右编号为 111 到 nnn。 第 iii 种馅儿具有一个非负整数的属性值 aia_iai​。 每种馅儿的数…

.NET Core/Framework 创建委托以大幅度提高反射调用的性能

都知道反射伤性能&#xff0c;但不得不反射的时候又怎么办呢&#xff1f;当真的被问题逼迫的时候还是能找到解决办法的。为反射得到的方法创建一个委托&#xff0c;此后调用此委托将能够提高近乎直接调用方法本身的性能。&#xff08;当然 Emit 也能够帮助我们显著提升性能&…

[省选联考 2020 A/B 卷] 冰火战士(树状数组上二分)

文章目录problemsolution(10pts)code(10pts)solution(30pts)code(30pts)solution(60pts)code(60pts)solution(100pts)code(100pts)problem luogu-P6619 一场比赛即将开始。 每位战士有两个属性&#xff1a;温度和能量。 有两派战士&#xff1a; 冰系战士的技能会对周围造成…

P1829 [国家集训队]Crash的数字表格 / JZPTAB

P1829 [国家集训队]Crash的数字表格 / JZPTAB 题意&#xff1a; 求∑i1n∑j1mlcm(i,j)\sum_{i1}^{n}\sum_{j1}^{m}lcm(i,j)∑i1n​∑j1m​lcm(i,j) 1<n<m<1e7 结果mod20101009 题解&#xff1a; 跟这个题P3911 最小公倍数之和很相近&#xff0c;但是本题数据范围大…

C# 跨设备前后端开发探索

每个人都拥有 好奇心&#xff0c;好奇心驱使着我们总是去尝试做一些有趣的事情。带起你的好奇心&#xff0c;本文将使用 C# 开发各种各样好玩的东西。每个人都拥有 好奇心&#xff0c;好奇心驱使着我们总是去尝试做一些有趣的事情。比如这件事&#xff1a;在好奇心的驱使下&…

Docker最全教程之Python爬网实战(二十二)

Python目前是流行度增长最快的主流编程语言&#xff0c;也是第二大最受开发者喜爱的语言&#xff08;参考Stack Overflow 2019开发者调查报告发布&#xff09;。笔者建议.NET、Java开发人员可以将Python发展为第二语言&#xff0c;一方面Python在某些领域确实非常犀利&#xff…

P2870 [USACO07DEC]Best Cow Line G

P2870 [USACO07DEC]Best Cow Line G 题意&#xff1a; 给你一个字符串&#xff0c;每次从首或尾取一个字符组成字符串&#xff0c;问所有能够组成的字符串中字典序最小的一个。 题解&#xff1a; 现在要组成字典序最小的&#xff0c;那我们每次就尽可能取小的 我们从两端开…

[APIO2014] 序列分割(斜率优化dp)

problem luogu-P3648 你正在玩一个关于长度为 nnn 的非负整数序列的游戏。这个游戏中你需要把序列分成 k1k1k1 个非空的块。 为了得到 k1k1k1 块&#xff0c;你需要重复下面的操作 kkk 次&#xff1a; 选择一个有超过一个元素的块&#xff08;初始时你只有一块&#xff0c;…

中间件是什么?在.NET Core中的工作原理又是怎样的呢?

本文出自《从零开始学ASP.NET CORE MVC》推荐文章&#xff1a;ASP.NET Core appsettings.json文件ASP.NET Core 中的中间件(Middleware)在这个视频中&#xff0c;我们将了解&#xff0c;ASP.NET Core 中的中间件是 什么&#xff1f;中间件很重要&#xff0c;尤其是在你想当架构…

P2408 不同子串个数

P2408 不同子串个数 题意&#xff1a; 给你一个长为 n 的字符串&#xff0c;求不同的子串的个数。 我们定义两个子串不同&#xff0c;当且仅当有这两个子串长度不一样或者长度一样且有任意一位不一样。 子串的定义&#xff1a;原字符串中连续的一段字符组成的字符串。 题解…

[SDOI2016] 生成魔咒(后缀数组SA + st表 + set)动态不同子串个数

problem luogu-P4070 魔咒串由许多魔咒字符组成&#xff0c;魔咒字符可以用数字表示。例如可以将魔咒字符 1,21,21,2 拼凑起来形成一个魔咒串 [1,2][1,2][1,2]。 一个魔咒串 S 的非空字串被称为魔咒串 S 的生成魔咒。 例如 S[1,2,1]S[1,2,1]S[1,2,1] 时&#xff0c;它的生成…

P4248 [AHOI2013]差异

P4248 [AHOI2013]差异 题意&#xff1a; ∑1≤i<j≤nlen(Ti)len(Tj)−2∗lcp(Ti,Tj)\sum_{1\leq i<j\leq n}len(T_{i})len(T_{j})-2*lcp(T_{i},T_{j})∑1≤i<j≤n​len(Ti​)len(Tj​)−2∗lcp(Ti​,Tj​) 题解&#xff1a; ∑1≤i<j≤nlen(Ti)len(Tj)\sum_{1\le…

从高德采集最新的省市区三级坐标和行政区域边界,用js在浏览器中运行

本文描述的是对国家统计局于2019-01-31发布的《2018年统计用区划代码和城乡划分代码(截止2018年10月31日)》中省市区三级的坐标和行政区域边界的采集。本文更新&#xff08;移步查阅&#xff09;&#xff1a;19-04-15 新采集了2018的省市区三级的坐标和行政区域边界数据csv格式…