V字钩爪
题目链接
我们首先的想法是想把相互独立的点分开,把会产生影响的点放一起,那么哪些是会产生影响的点呢。这里是相隔 k kk 即可产生相互影响,那实际上就是处在 k kk 的一个同余系下的点就是会产生影响的,我们可以把处在同一同余系下的点如下代码拆出来扔进一个 v e c t o r vectorvector 里面去,于是我们就可以独立考虑每个同余系的答案。
for (int i = 1; i <= n; ++i) {
g[i % k].push_back(a[i]);
}
那么对于同一个 i % k i\% ki%k (同余系),他们的值如何算呢,实际上他们的限制就是一次操作只能取相邻的两个点,那么我们可以通过 d p dpdp 解决这个问题。
我们设 d p [ i ] [ 0 / 1 ] dp[i][0/1]dp[i][0/1] 为考虑到了第 i ii 个物品(下标从 0 00 开始),且第 i ii 个物品不取 ( 0 ) (0)(0) 或者取 ( 1 ) (1)(1) 情况下所能得到的最大值。
我们这里设第 i ii 个物品价值为 v a l [ i ] val[i]val[i] ,且当前同余系下共有 m mm 个物品,那么我们有:
d p [ 0 ] [ 0 ] = d p [ 0 ] [ 1 ] = 0 dp[0][0]=dp[0][1]=0dp[0][0]=dp[0][1]=0
d p [ i ] [ 0 ] = m a x ( d p [ i − 1 ] [ 0 ] , d p [ i − 1 ] [ 1 ] ) ( i > 0 ) dp[i][0] = max(dp[i - 1][0], dp[i-1][1])\ (i>0)dp[i][0]=max(dp[i−1][0],dp[i−1][1]) (i>0)
d p [ i ] [ 0 ] = d p [ i − 1 ] [ 0 ] + v a l [ i − 1 ] + v a l [ i ] ( i > 0 ) dp[i][0] = dp[i - 1][0]+val[i-1]+val[i]\ (i>0)dp[i][0]=dp[i−1][0]+val[i−1]+val[i] (i>0)
最终 m a x ( d p [ m − 1 ] [ 0 ] , d p [ m − 1 ] [ 1 ] ) max(dp[m-1][0], dp[m-1][1])max(dp[m−1][0],dp[m−1][1]) 为这一同余系的答案,最后我们把每种情况求和即是最终答案。
#include <bits/stdc++.h>
#define lson (rt<<1)
#define rson ((rt<<1)|1)
using namespace std;
typedef long long ll;
const int N = 1e6 + 10;
int n, k, a[N], vis[N];
ll dp[N][2];
vector<int> g[N];
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
}
for (int i = 1; i <= n; ++i) {
g[i % k].push_back(a[i]);
}
ll ans = 0;
for (int i = 0; i < k; ++i) {
if (g[i].empty()) continue;
int m = (int)g[i].size();
for (int j = 1; j < m; ++j) {
dp[j][0] = max(dp[j - 1][0], dp[j - 1][1]);
dp[j][1] = dp[j - 1][0] + g[i][j] + g[i][j - 1];
}
ans += max(dp[m - 1][0], dp[m - 1][1]);
}
cout << ans << endl;
}