【单调队列/单调栈/斜率优化DP】CF 1077F2,319C,372C,675E,1304F2,1107G,1083E,939F,311B

再次搁浅了题解咕咕咕咕

  • T1:CF1077F2 Pictures with Kittens (hard version)
    • title
    • solution
    • code
  • T2:CF319C Kalila and Dimna in the Logging Industry
    • title
    • solution
    • code
  • T3:CF372C Watching Fireworks is Fun
    • title
    • solution
    • code
  • T4:CF675E Trains and Statistic
    • title
    • solution
    • code
  • T5:CF1304F2 Animal Observation (hard version)
    • title
    • solution
    • code
  • T6:CF1107G Vasya and Maximum Profit
    • title
    • solution
    • code
  • T7:CF1083E The Fair Nut and Rectangles
    • title
    • solution
    • code
  • T8:CF939F Cutlet
    • title
    • solution
    • code
  • T9:CF311B Cats Transport
    • title
    • solution
    • code

T1:CF1077F2 Pictures with Kittens (hard version)

title

solution

code

#include 
#include 
#include 
#include 
using namespace std;
#define ll long long
deque < pair < int, ll > > q;
int n, m, k;
ll ans, sum;
ll a[5005];
ll dp[5005][5005];
/*
dp[i][j]=max(dp[p-1][j-1]+a[p]) {p=[i-k+1,i]}
前i个数中选j个的最大值
用单调队列优化dp[p-1][j-1]+a[p](因为与i无关) 
*/
int main() {
	scanf( "%d %d %d", &n, &k, &m );
	for( int i = 1;i <= n;i ++ )
		scanf( "%lld", &a[i] );
	memset( dp, -1, sizeof( dp ) );
	for( int i = 0;i < k;i ++ ) dp[i][0] = 0;//前k-1个不选也是可以成立的
	//为什么不是0~n呢?
	//因为如果n>k,题目要求每连续的k个元素都至少有一个要选
	//所以显然dp[n][0]是不成立的 
	for( int j = 1;j <= m;j ++ ) {
		while( ! q.empty() ) q.pop_back();
		for( int i = j;i <= n;i ++ ) {
			while( ! q.empty() && q.front().first < i - k + 1 ) q.pop_front();
			if( ~ dp[i - 1][j - 1] ) {//这个相当于i作上一层状态,去转移后面的 
				while( ! q.empty() && q.back().second <= dp[i - 1][j - 1] + a[i] )
					q.pop_back();
				q.push_back( make_pair( i, dp[i - 1][j - 1] + a[i] ) );
			}
			if( ! q.empty() ) dp[i][j] = q.front().second;//这个相当于i作当前层状态,被上层状态转移 
		}
	}
	printf( "%lld", dp[n][m] );
	return 0;
}

T2:CF319C Kalila and Dimna in the Logging Industry

title

solution

只会往后砍,绝对不吃回头草
d p [ i ] dp[i] dp[i]表示砍掉第 i i i棵树的最小花费
枚举前面砍掉的数的最大编号

d p [ i ] = d p [ j ] + a [ i ] ∗ b [ j ] dp[i]=dp[j]+a[i]*b[j] dp[i]=dp[j]+a[i]b[j]
d p [ i ] = d p [ k ] + a [ i ] ∗ b [ k ] dp[i]=dp[k]+a[i]*b[k] dp[i]=dp[k]+a[i]b[k]

m i n ( d p [ j ] + a [ i ] ∗ b [ j ] , d p [ k ] + a [ i ] ∗ b [ k ] ) min(dp[j]+a[i]*b[j],dp[k]+a[i]*b[k]) min(dp[j]+a[i]b[j],dp[k]+a[i]b[k])

如果 k k k优于 j j j则有
d p [ j ] + a [ i ] ∗ b [ j ] > = d p [ k ] + a [ i ] ∗ b [ k ] dp[j]+a[i]*b[j]>=dp[k]+a[i]*b[k] dp[j]+a[i]b[j]>=dp[k]+a[i]b[k]
d p [ j ] − d p [ k ] > = a [ i ] ∗ ( b [ k ] − b [ j ] ) j < k , b [ j ] > b [ k ] dp[j]-dp[k]>=a[i]*(b[k]-b[j]) {jb[k]} dp[j]dp[k]>=a[i](b[k]b[j])j<k,b[j]>b[k]
( d p [ j ] − d p [ k ] ) / ( b [ k ] − b [ j ] ) < = a [ i ] (dp[j]-dp[k])/(b[k]-b[j])<=a[i] (dp[j]dp[k])/(b[k]b[j])<=a[i]

code

#include 
#include 
using namespace std;
#define ll long long
int n, head = 1, tail;
ll high[100005], cost[100005], deq[100005], dp[100005];

double calc( int j, int k ) {
	return ( dp[j] - dp[k] ) * 1.0 / ( cost[k] - cost[j] );
}

int main() {
	scanf( "%d", &n );
	for( int i = 1;i <= n;i ++ )
		scanf( "%lld", &high[i] );
	for( int i = 1;i <= n;i ++ )
		scanf( "%lld", &cost[i] );
	for( int i = 1;i <= n;i ++ ) {
		while( head < tail && calc( deq[head], deq[head + 1] ) <= high[i] ) head ++;
		if( head <= tail ) dp[i] = dp[deq[head]] + high[i] * cost[deq[head]];
		while( head < tail && calc( deq[tail - 1], deq[tail] ) >= calc( deq[tail], i ) ) tail --;
		deq[++ tail] = i;
	}
	printf( "%lld", dp[n] );
	return 0;
}

T3:CF372C Watching Fireworks is Fun

title

solution

希望谢特姐姐崽也可以和自己最爱的人——谢特姐姐一起看一场美丽绚烂的烟花盛宴

code

#include 
#include 
#include 
using namespace std;
#define ll long long
int n, m, d, head, tail;
ll sum, ans;
int deq[150005];
ll a[305], b[305], t[305];
ll f[2][150005];

ll Fabs( ll x ) {
	return ( x > 0 ) ? x : -x;
}

int main() {
	scanf( "%d %d %d", &n, &m, &d );
	for( int i = 1;i <= m;i ++ ) {
		scanf( "%lld %lld %lld", &a[i], &b[i], &t[i] );
		sum += b[i];
	}
	for( int i = 1;i <= n;i ++ )
		f[1][i] = Fabs( a[1] - i );
	for( int i = 2;i <= m;i ++ ) {
		int now = i & 1, last = i & 1 ^ 1;
		memset( f[now], 0x3f, sizeof( f[now] ) );
		ll T = t[i] - t[i - 1];
		head = 1, tail = 0;
		for( int j = 1;j <= n;j ++ ) {
			while( head <= tail && deq[head] < j - T * d ) head ++;
			while( head <= tail && f[last][deq[tail]] >= f[last][j] ) tail --;
			deq[++ tail] = j;
			f[now][j] = min( f[now][j], f[last][deq[head]] + Fabs( a[i] - j ) );
		}
		head = 1, tail = 0;
		for( int j = n;j;j -- ) {
			while( head <= tail && deq[head] > j + T * d ) head ++;
			while( head <= tail && f[last][deq[tail]] >= f[last][j] ) tail --;
			deq[++ tail] = j;
			f[now][j] = min( f[now][j], f[last][deq[head]] + Fabs( a[i] - j ) );
		}
	}
	ll ans = 0x7f7f7f7f;
	for( int i = 1;i <= n;i ++ )
		ans = min( ans, f[m & 1][i] );
	printf( "%lld", sum - ans );
	return 0;
}

T4:CF675E Trains and Statistic

title

solution

code

#include 
#include 
#include 
using namespace std;
#define ll long long
deque < int > q;
int n;
ll ans;
ll a[100005], dp[100005];

int main() {
	scanf( "%d", &n );
	for( int i = 1;i < n;i ++ )
		scanf( "%lld", &a[i] );
	dp[n - 1] = ans = 1;
	q.push_back( n - 1 );
	for( int i = n - 2;i;i -- ) {
		int k = * ( upper_bound( q.rbegin(), q.rend(), a[i] ) - 1 );
		dp[i] = dp[k] + ( n - a[i] ) + ( k - i );
		ans += dp[i];
		while( ! q.empty() && a[q.back()] <= a[i] ) q.pop_back();
		q.push_back( i );
	}
	printf( "%lld", ans );
	return 0;
}

T5:CF1304F2 Animal Observation (hard version)

title

solution

code

#include 
#include 
#include 
using namespace std;
#define MAXM 20005
int n, m, k, g;
int tree[MAXM << 2], lazy[MAXM << 2];
int s[55][MAXM], a[55][MAXM];
int f[55][MAXM];

void build( int t, int l, int r, int i ) {
	if( l == r ) {
		tree[t] = f[i][l] + s[i + 1][l + k - 1] - s[i + 1][l - 1];
		return;
	}
	int mid = ( l + r ) >> 1;
	build( t << 1, l, mid, i ), build( t << 1 | 1, mid + 1, r, i );
	tree[t] = max( tree[t << 1], tree[t << 1 | 1] );
}

void push_down( int t ) {
	if( lazy[t] ) {
		tree[t << 1] += lazy[t], tree[t << 1 | 1] += lazy[t];
		lazy[t << 1] += lazy[t], lazy[t << 1 | 1] += lazy[t];
		lazy[t] = 0;
	}
}

void modify( int t, int l, int r, int L, int R, int val ) {
	if( L <= l && r <= R ) {
		lazy[t] += val, tree[t] += val;
		return;
	}
	push_down( t );
	int mid = ( l + r ) >> 1;
	if( L <= mid ) modify( t << 1, l, mid, L, R, val );
	if( mid < R ) modify( t << 1 | 1, mid + 1, r, L, R, val );
	tree[t] = max( tree[t << 1], tree[t << 1 | 1] );
}

void add( int i, int pos ) {//重复贡献 
	if( pos ) modify( 1, 1, g, max( 1, pos - k + 1 ), min( g, pos ), -a[i][pos] );
}

void del( int i, int pos ) {
	if( pos ) modify( 1, 1, g, max( 1, pos - k + 1 ), min( pos, g ), a[i][pos] );
}

int main() {
	scanf( "%d %d %d", &n, &m, &k );
	for( int i = 1;i <= n;i ++ )
		for( int j = 1;j <= m;j ++ )
			scanf( "%d", &a[i][j] ), s[i][j] = s[i][j - 1] + a[i][j];
	g = m - k + 1;
	for( int i = 1;i <= n;i ++ ) {
		if( i > 1 )
			for( int j = 1;j < k;j ++ )
				add( i, j );
		for( int j = 1;j + k - 1 <= m;j ++ ) {
			int l = j, r = j + k - 1;
			if( i == 1 ) f[i][j] = s[1][r] - s[1][l - 1];
			else del( i, l - 1 ), add( i, r ), f[i][j] = tree[1] + s[i][r] - s[i][l - 1];
		}
		memset( tree, 0, sizeof( tree ) );
		memset( lazy, 0, sizeof( lazy ) );
		if( i < n )	build( 1, 1, g, i );
	}
	int ans = 0;
	for( int i = 1;i <= m;i ++ )
		ans = max( ans, f[n][i] );
	printf( "%d", ans );
	return 0;
}

T6:CF1107G Vasya and Maximum Profit

title

solution

code

#include 
#include 
using namespace std;
#define ll long long
struct node {
	ll f, maxx, ans;
	node(){}
	node( ll x, ll y, ll z ) {
		f = x, maxx = y, ans = z;
	}
}q[300005];
int n, top;
ll a, ans;
ll d[300005], F[300005], sum[300005];

ll calc( ll x, ll y ) {
	return ( x - y ) * ( x - y );
}

int main() {
	scanf( "%d %lld", &n, &a );
	for( int i = 1;i <= n;i ++ ) {
		ll c;
		scanf( "%lld %lld", &d[i], &c );
		sum[i] = sum[i - 1] + c;
		F[i] = i * a - sum[i];
	}
	ans = max( 0ll, a - sum[n] + sum[n - 1] );
	q[++ top] = node( F[n], 0, F[n] );
	q[0].ans = -1e17;
	for( int i = n - 1;i;i -- ) {
		ll temp = -1e17;
		while( top && q[top].maxx <= d[i + 1] - d[i] ) temp = max( temp, q[top].f ), top --;
		if( temp != -1e17 )
			q[++ top] = node( temp, d[i + 1] - d[i], max( q[top - 1].ans, temp - calc( d[i + 1], d[i] ) ) );
		q[++ top] = node( F[i], 0, max( F[i], q[top - 1].ans ) );
		ans = max( ans, q[top].ans - a * i + sum[i - 1] + a );
	}
	printf( "%lld", ans );
	return 0;
}

T7:CF1083E The Fair Nut and Rectangles

title

solution

code

#include 
#include 
using namespace std;
#define ll long long
#define MAXN 1000005
struct node {
	ll x, y, a;
}v[MAXN];
int n;
int deq[MAXN];
ll f[MAXN];

bool cmp( node s, node t ) {
	return s.y > t.y;
}
/*
f[i]: 做到排序后的第i个矩形了,选择这个矩形,面积并减去权值和的最大值为f[i]
f[i]=max(f[j]+x[i]*y[i]-x[j]*y[i]-a)

j x[j]<=x[k]
f[j] -x[j]*y[i]<=f[k] -x[k]*y[i]
f[j]-f[k]<=(x[j]-x[k])*y[i]
(f[j]-f[k])/(x[j]-x[k])>=y[i]
*/
double slope( int j, int k ) {
	return ( f[j] - f[k] ) * 1.0 / ( v[j].x - v[k].x );
}

int main() {
	scanf( "%d", &n );
	for( int i = 1;i <= n;i ++ )
		scanf( "%lld %lld %lld", &v[i].x, &v[i].y, &v[i].a );
	sort( v + 1, v + n + 1, cmp );
	int head = 1, tail = 0;
	ll ans = 0;
	for( int i = 1;i <= n;i ++ ) {
		while( head < tail && slope( deq[head], deq[head + 1] ) >= v[i].y )
			head ++;
		f[i] = v[i].x * v[i].y - v[i].a;
		f[i] = max( f[i], f[deq[head]] + v[i].x * v[i].y - v[deq[head]].x * v[i].y - v[i].a );
		ans = max( ans, f[i] );
		while( head < tail && slope( deq[tail - 1], deq[tail] ) <= slope( deq[tail], i ) )
			tail --;
		deq[++ tail] = i;
	}
	printf( "%lld", ans );
	return 0;
}

T8:CF939F Cutlet

title

solution

code

#include 
#include 
#include 
using namespace std;
#define ll long long
const int inf = 1e9;
int n, k, head, tail;
int deq[200010];
ll l, r;
ll dp[2][200010];

int main() {
	scanf( "%d %d", &n, &k );
	for( int i = 1;i <= n;i ++ )
		dp[0][i] = inf;
	int now = 0;
	while( k -- ) {
		scanf( "%lld %lld", &l, &r );
		now ^= 1, head = 1, tail = 0;
		memcpy( dp[now], dp[now ^ 1], sizeof( dp[now ^ 1] ) );
		for( int j = 0;j <= min( r, 1ll * n );j ++ ) {
			while( head <= tail && deq[head] < j - ( r - l ) )
				head ++;
			while( head <= tail && dp[now ^ 1][deq[tail]] >= dp[now ^ 1][j] )
				tail --;
			deq[++ tail] = j;
			dp[now][j] = min( dp[now][j], dp[now ^ 1][deq[head]] + 2 );
		}
		head = 1, tail = 0;
		for( int j = r;~ j;j -- ) {
			while( head <= tail && deq[head] < l - j )
				head ++;
			while( head <= tail && dp[now ^ 1][deq[tail]] >= dp[now ^ 1][r - j] )
				tail --;
			deq[++ tail] = r - j;
			dp[now][j] = min( dp[now][j], dp[now ^ 1][deq[head]] + 1 );
		}
	}
	if( dp[now][n] ^ inf ) return ! printf( "Full\n%lld", dp[now][n] );
	else return ! printf( "Hungry" );
	return 0;
}

T9:CF311B Cats Transport

title

solution

code

#include 
#include 
#include 
using namespace std;
#define ll long long
int n, m, p, head, tail;
int deq[100005];
ll d[100005], T[100005], Sum[100005];
ll f[100005][105];

double slope( int j, int k, int i ) {
	return ( f[j][i] - f[k][i] + Sum[j] - Sum[k] ) * 1.0 / ( j - k );
}

int main() {
	scanf( "%d %d %d", &n, &m, &p );
	for( int i = 2;i <= n;i ++ )
		scanf( "%lld", &d[i] ), d[i] += d[i - 1];
	for( int i = 1;i <= m;i ++ ) {
		ll h, t;
		scanf( "%lld %lld", &h, &t );
		T[i] = t - d[h];
	}
	if( m <= p ) return ! printf( "0" );
	sort( T + 1, T + m + 1 );
	for( int i = 1;i <= m;i ++ )
		Sum[i] = Sum[i - 1] + T[i];
	memset( f, 0x7f, sizeof( f ) );
	f[0][0] = 0;
	for( int i = 1;i <= p;i ++ ) {
		head = tail = 1, deq[0] = 0;
		for( int j = 1;j <= m;j ++ ) {
			while( head < tail && slope( deq[head], deq[head + 1], i - 1 ) <= T[j] )
				++ head;
			f[j][i] = f[deq[head]][i - 1] + T[j] * ( j - deq[head] ) - Sum[j] + Sum[deq[head]];
			while( head < tail && slope( deq[tail - 1], deq[tail], i - 1 ) >= slope( deq[tail], j, i - 1 ) )
				-- tail;
			deq[++ tail] = j;
		}
	}
	printf( "%lld", f[m][p] );
	return 0;
}

你可能感兴趣的:(#,单调队列,#,单调栈,#,斜率优化)