牛客练习赛85 F.音游家的谱面(Hard version)(dp的多种优化)

Posted issue是fw

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了牛客练习赛85 F.音游家的谱面(Hard version)(dp的多种优化)相关的知识,希望对你有一定的参考价值。

LINK


T 1 T1 T1

综合性很强的一题

首先可以定义 f [ i ] [ j ] [ q ] f[i][j][q] f[i][j][q]表示当前接到了 [ 1 , i ] [1,i] [1,i]的音符,左手在 j j j右手在 q q q的最小时间

但是发现想接到第 i i i个音符,必然有一只手在 a i a_i ai位置

所以重新定义 f [ i ] [ j ] f[i][j] f[i][j]表示当前接到了 [ 1 , i ] [1,i] [1,i]的音符,一只手在 a i a_i ai处,一只手在 j j j

然后 O ( n m ) O(nm) O(nm)枚举状态,转移复杂度 O ( n ) O(n) O(n),总体复杂度 O ( n 2 m ) O(n^2m) O(n2m)

代码LINK

T 2 T2 T2

显然枚举状态的 O ( n m ) O(nm) O(nm)是必要的,考虑优化 O ( n ) O(n) O(n)的转移

看上去都是 a b s abs abs不好考虑,那就考虑 f [ i − 1 ] [ j ] f[i-1][j] f[i1][j]能转移到哪些位置来

无非就是分俩种情况,一是 j j j位置的手移动到 a i a_i ai,二是 a i − 1 a_{i-1} ai1的手移动到 a i a_i ai

此时有一个小贪心,设此时为情况一,花费的时间为 l i m = a b s ( j − a i ) lim=abs(j-a_i) lim=abs(jai)

那么另一只手在这 l i m lim lim的时间内只能在 [ m a x ( 1 , a i − 1 − l i m ) , m i n ( n , a i − 1 + l i m ) ] \\rm [max(1,a_{i-1}-lim),min(n,a_{i-1}+lim)] [max(1,ai1lim),min(n,ai1+lim)]内移动

这段区间都能被转移到,所以可以用线段树去更新.

不在这段区间内的状态不需要考虑,因为需要花费的时间大于 l i m lim lim,然而有一只手已经到了 a i a_i ai,所以是划不来的

时间复杂度 O ( n m l o g ( n ) ) O(nmlog(n)) O(nmlog(n))

是个不错的复杂度,然而还是无法通过本题

代码LINK

T 3 T3 T3

.考虑从上一次按到音符的手移动到这次按音符的轨道去,花费 l i m = a b s ( a i − 1 − a i ) lim=abs(a_{i-1}-a_{i}) lim=abs(ai1ai)

对于每个 f [ i ] [ j ] f[i][j] f[i][j]来说,能被 f [ i − 1 ] [ q ] f[i-1][q] f[i1][q]更新当且仅当 q ∈ [ m a x ( 1 , j − l i m ) , m a x ( n , j + l i m ) ] \\rm q\\in[max(1,j-lim),max(n,j+lim)] q[max(1,jlim),max(n,j+lim)]

发现这个区间是单调右移的,显然可以用一个单调队列优化掉最大值

.考虑从自由手 q q q移动到这次的音符轨道去,花费 l i m = a b s ( q − a i ) lim=abs(q-a_{i}) lim=abs(qai)

对于每个 f [ i − 1 ] [ q ] f[i-1][q] f[i1][q]来说,能更新的范围是以 a i − 1 a_{i-1} ai1为中心的长度为 2 ∗ l i m 2*lim 2lim的区间长度

也就是更新区间 [ m a x ( 1 , a i − 1 − l i m ) , m i n ( n , a i − 1 + l i m ) ] = [ L , R ] \\rm [max(1,a_{i-1}-lim),min(n,a_{i-1}+lim)]=[L,R] [max(1,ai1lim),min(n,ai1+lim)]=[L,R]

有了中心点就好办了,我们分成 [ 1 , a i − 1 ] [1,a_{i-1}] [1,ai1] [ a i − 1 , n ] [a_{i-1},n] [ai1,n]分别计算贡献

直接用 f [ i − 1 ] [ q ] + l i m f[i-1][q]+lim f[i1][q]+lim去更新 f [ i ] [ L ] \\rm f[i][L] f[i][L],然后对 f [ i ] [ 1... a i − 1 ] f[i][1...a_{i-1}] f[i][1...ai1]从左到右取一遍 m i n min min

f [ i − 1 ] [ q ] + l i m f[i-1][q]+lim f[i1][q]+lim去更新 f [ i ] [ R ] f[i][R] f[i][R],然后对 f [ i ] [ a i − 1 . . . n ] f[i][a_{i-1}...n] f[i][ai1...n]从又往左取一遍 m i n min min

这个非常好理解,距离 a i − 1 a_{i-1} ai1越近越容易被更新

综上所诉,整体复杂度为 O ( n m ) O(nm) O(nm)

#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
const int inf = 0x3f3f3f3f;
const int maxn = 5e3+10;
int n,m,f[maxn][maxn],a[maxn],pre[maxn][maxn],l[maxn],r[maxn];
typedef pair<int,int>p;
p fl[maxn],fr[maxn],q[maxn];
void dfs(int fir,int sec)
{
	if( fir==0 )	return;
	dfs( fir-1,pre[fir][sec] );
	cout << f[fir][sec] << " ";
}
void solve()
{
	int ans = inf, chu = 0;
	for(int i&

以上是关于牛客练习赛85 F.音游家的谱面(Hard version)(dp的多种优化)的主要内容,如果未能解决你的问题,请参考以下文章

牛客练习赛70 F.曲调(离线,思维,权值线段树)

牛客练习赛C魔法学院(hard version) 并查集加速

牛客练习赛C魔法学院(hard version) 并查集加速

牛客练习赛85 D.数学家的迷题(bitset暴力)

牛客练习赛85 A~D题题解

牛客练习赛85 B 音乐家的曲调(尺取法)