整理 斜率or單調佇列優化dp

2021-06-29 05:20:56 字數 4339 閱讀 9223

題意:求乙個序列的子區間滿足長度大於k且所有數平均值最大

周源**裡的題。。之前有人說周源講的是錯的 其實應該是沒什麼問題的 可以o(n)求出

不過這題hdu上的資料不知道怎麼了 = = 反正我在網上找的ac**們全都tle。。。。

總之……意思明白就好 反正也是入門題……

#include #include #include #include using namespace std;

int read()

while(c >= '0' && c <= '9')

return sign*n;

}int n, k;

int a[100005];

double sum[100005];

namespace queue

inline void push_back(int x)

inline void pop_back()

inline void pop_front()

inline int front()

inline int second()

inline int back()

inline int before()

inline int size()

}inline double get_k(int i, int j)

int main()

using namespace queue;

double ans = 1e-100; init();

for(int i = k; i <= n; ++i)

printf("%.2f\n", ans);

} return 0;

}

題意:把乙個集合 分成若干個子集合 每個集合的cost為最大值與最小值差的平方 求最大cost的最小值

和之前摩天輪那道題是一樣的。。先排個序 很明顯每個集合是要取連續的一段區間

那麼dp[i][j]表示前i個人分成了j個區間的最大cost的最小值。。於是dp[i][j] = max

然後展開以後就可以斜率優化了……還有就是第二維可以滾動。。

說實話這題寫的我略痛苦。。因為還是不太熟tat

#include #include #include using namespace std;

int read()

while(c >= '0' && c <= '9')

return sign*n;

}const int nmax = 10005;

int n, m;

int a[nmax], sqr[nmax];

int dp[nmax][2], g[nmax];

namespace queue

inline void push_back(int x)

inline void pop_back()

inline void pop_front()

inline int front()

inline int second()

inline int back()

inline int before()

inline int size()

}inline double getk(int i, int j)

int main()

sort(a + 1, a + n + 1);

for(int i = 1; i <= n; ++i) sqr[i] = a[i] * a[i];

using namespace queue;

for(int j = 1; j <= m; ++j)

}printf("case %d: %d\n", ++cas, dp[n][m & 1]);

} return 0;

}

題意:找出乙個數列中的最長的乙個子區間 滿足最大值和最小值之差在[m, k]之間

開兩個單調佇列乙個維護遞增乙個維護遞減就可以了。。然後每次判斷隊首合不合法。。。並更新答案。。。

這題我最開始佇列初始化為a[1]就一直會掛 = =我也不知道為什麼

#include #include #include using namespace std;

int read()

while(c >= '0' && c <= '9')

return sign*n;

}int n, m, k;

int a[100005];

struct queue

inline void push_back(int x)

inline void pop_back()

inline void pop_front()

inline int front()

inline int back()

inline int size()

}q[2];

int main()

else

}if(a[q[0].front()] - a[q[1].front()] >= m) ans = max(ans, i - left);

} printf("%d\n", ans);

} return 0;

}

題意:……中文題就不寫了……

然後這題的公式還是蠻好推的。。但是因為特別長所以要注意細節。。。

a是小於0的 我們要求的是最大值 那麼就維護乙個上凸包(其實也可以轉化成下凸包。。都一樣)

f[i] = max( f[j] + a*(s[i]-s[j])^2 + b*(s[i]-s[j]) + c) 

= ( f[j] + a*s[j]^2  - b*s[j] ) + ( a*s[i]^2 +b*s[i]+c )  - ( 2*a*s[i]*s[j] )

分三塊。。很明顯是不是。。

#include #include using namespace std;

typedef long long ll;

const int nmax = 1000005;

int n;

ll a[nmax], sum[nmax], sqr[nmax], a, b, c;

ll dp[nmax], f[nmax];

namespace queue

inline void push_back(int x)

inline void pop_back()

inline void pop_front()

inline int front()

inline int second()

inline int back()

inline int before()

inline int size()

}double get_k(int i, int j)

int main()

using namespace queue; init();

for(int i = 1; i <= n; ++i)

cout << dp[n] << endl;

return 0;

}

題意:把n個字母分成若干行 每個字母有個ci 然後每行的cost為sigma(ci) + m 求總cost的最小值

和上面那題差不多 而且公式還簡單些 = =

#include #include using namespace std;

typedef long long ll;

const int nmax = 500005;

int n, m;

ll a[nmax], sum[nmax], sqr[nmax];

ll dp[nmax], f[nmax];

namespace queue

inline void push_back(int x)

inline void pop_back()

inline void pop_front()

inline int front()

inline int second()

inline int back()

inline int before()

inline int size()

}double get_k(int i, int j)

int main()

using namespace queue; init();

for(int i = 1; i <= n; ++i)

cout << dp[n] << endl;

} return 0;

}

題解:

單調佇列DP 斜率DP

考慮到知識點是單調佇列,考慮怎麼使用單調佇列 首先說明一點,小天使可以選擇當前時刻鋼琴是否移動 並非一次就要一段時間 考慮dp方程,由於每次只能走乙個方向,選擇不了,其實就相當於乙個一維的dp了 以往上 北 為例 t為第t段時間 f t i j max 變形為 f t i j max i 然後把 f...

模型化理解單調佇列優化和斜率優化DP

設a x b x c x d x 為僅關於x的一元函式 dp i a i b j 中的最小 大值 i k j dp i dp j i j w 選自hdu3401 a i i w b j dp j j w 維護b j 的最大合法值進行轉移即可 建立一層迴圈i 1 n 每次先用i k更新單調佇列隊頭位置...

動態規劃 單調斜率優化DP

acwing 1087.修剪草坪 旅行商問題 輸入樣例 641 351 23 輸出樣例 acwing 1087.修剪草坪 動態規劃 f i max f i 1 f i j 1 sum i j sum i f i 表示從前i個中選,且合法的方案數。令x i j,則有 f i min f i 1 f x...