题意:给你一个只包含".“和”#"的序列,你需要覆盖这个序列,有三种覆盖方式:
覆盖 “.” 价值为G1
覆盖"..“价值为G2
覆盖”.#."价值为G3
每个点只能被覆盖一遍,但是不必覆盖所有的点,第一中覆盖方式最多只能有K个。为最大化覆盖价值和。最多50个”#“号
显然是个dp,dp[i][j][2]为到达第i个井号,用了j个第一覆盖,最后一个井号有没有被覆盖。pos[i]为第i个井号的位置转移方程为:
s
u
m
=
p
o
s
[
i
]
−
p
o
s
[
i
−
1
]
−
1
sum = pos[i]-pos[i-1]-1
sum=pos[i]−pos[i−1]−1
d p [ i ] [ j ] [ 0 ] = max 1 < = c < = m i n ( k , s u m ) { d p [ i − 1 ] [ c ] [ 0 ] + G 1 ∗ ( s u m − c ) + G 2 ∗ ⌊ c 2 ⌋ } dp[i][j][0]=\max_{1<=c<=min(k, sum)}\{dp[i-1][c][0] + G1*(sum-c)+G2* \lfloor \frac{c}{2}\rfloor \} dp[i][j][0]=1<=c<=min(k,sum)max{dp[i−1][c][0]+G1∗(sum−c)+G2∗⌊2c⌋}
d p [ i ] [ j ] [ 0 ] = max 1 < = c < = m i n ( k , s u m − 1 ) { d p [ i − 1 ] [ c ] [ 1 ] + G 1 ∗ ( s u m − 1 − c ) + G 2 ∗ ⌊ c 2 ⌋ } dp[i][j][0]=\max_{1<=c<=min(k, sum-1)}\{dp[i-1][c][1] + G1*(sum-1-c)+G2* \lfloor \frac{c}{2}\rfloor \} dp[i][j][0]=1<=c<=min(k,sum−1)max{dp[i−1][c][1]+G1∗(sum−1−c)+G2∗⌊2c⌋}
d p [ i ] [ j ] [ 1 ] = max 1 < = c < = m i n ( k , s u m − 1 ) { d p [ i − 1 ] [ c ] [ 0 ] + G 1 ∗ ( s u m − 1 − c ) + G 2 ∗ ⌊ c 2 ⌋ + G 3 } dp[i][j][1]=\max_{1<=c<=min(k, sum-1)}\{dp[i-1][c][0] + G1*(sum-1-c)+G2* \lfloor \frac{c}{2}\rfloor +G3\} dp[i][j][1]=1<=c<=min(k,sum−1)max{dp[i−1][c][0]+G1∗(sum−1−c)+G2∗⌊2c⌋+G3}
d
p
[
i
]
[
j
]
[
1
]
=
max
1
<
=
c
<
=
m
i
n
(
k
,
s
u
m
−
2
)
{
d
p
[
i
−
1
]
[
c
]
[
1
]
+
G
1
∗
(
s
u
m
−
2
−
c
)
+
G
2
∗
⌊
c
2
⌋
+
G
3
}
dp[i][j][1]=\max_{1<=c<=min(k, sum-2)}\{dp[i-1][c][1] + G1*(sum-2-c)+G2* \lfloor \frac{c}{2}\rfloor +G3\}
dp[i][j][1]=1<=c<=min(k,sum−2)max{dp[i−1][c][1]+G1∗(sum−2−c)+G2∗⌊2c⌋+G3}
很遗憾,因为式子中有个向下取值,我们无法通过提取c,然后求前缀最大值进行优化(最后时间复杂度为
O
(
c
n
t
∗
K
2
)
O(cnt*K^2)
O(cnt∗K2)cnt为井号的个数)。这时考虑贪心,显然,G1和G2可以有一个贪心。我们得知,对于题目情况,显然是要么尽量选G1,要么尽量选G2。我们不妨在dp的时候尽量选G2,然后最后考虑用G1替换G2。
这时有dp[i][j][2][k] 为考虑到第i个井号,一个覆盖了j个井号,最后一个井号有没有覆盖。有k个’.'没有被覆盖。的情况。为啥要这么记:因为这样我们就可以针对每一个情况,得知没有被覆盖的数量,和算出被G2覆盖的数量。方便最后的贪心。其中G2覆盖的数量sumg(n为序列总长,cnt为井号数量):
s
u
m
g
=
n
−
3
∗
j
−
k
−
(
c
n
t
−
j
)
sumg=n-3*j-k-(cnt-j)
sumg=n−3∗j−k−(cnt−j)
转移方程为:
s
u
m
=
p
o
s
[
i
]
−
p
o
s
[
i
−
1
]
−
1
sum = pos[i]-pos[i-1]-1
sum=pos[i]−pos[i−1]−1
d p [ i ] [ j ] [ 0 ] [ k + ( s u m m o d 2 ) ] = max 1 < = k < = c n t { d p [ i ] [ j ] [ 0 ] [ k ] + G 2 ∗ ⌊ s u m 2 ⌋ } dp[i][j][0][k+(sum\ mod\ 2)]=\max_{1<=k<=cnt}\{ dp[i][j][0][k]+G2*\lfloor \frac{sum}{2}\rfloor\} dp[i][j][0][k+(sum mod 2)]=1<=k<=cntmax{dp[i][j][0][k]+G2∗⌊2sum⌋}
d p [ i ] [ j ] [ 0 ] [ k + ( s u m − 1 m o d 2 ) ] = max 1 < = k < = c n t { d p [ i ] [ j ] [ 1 ] [ k ] + G 2 ∗ ⌊ s u m − 1 2 ⌋ } dp[i][j][0][k+(sum-1\ mod\ 2)]=\max_{1<=k<=cnt}\{ dp[i][j][1][k]+G2*\lfloor \frac{sum-1}{2}\rfloor\} dp[i][j][0][k+(sum−1 mod 2)]=1<=k<=cntmax{dp[i][j][1][k]+G2∗⌊2sum−1⌋}
d p [ i ] [ j ] [ 1 ] [ k + ( s u m − 1 m o d 2 ) ] = max 1 < = k < = c n t { d p [ i ] [ j − 1 ] [ 0 ] [ k ] + G 2 ∗ ⌊ s u m − 1 2 ⌋ + G 3 } dp[i][j][1][k+(sum-1\ mod\ 2)]=\max_{1<=k<=cnt}\{ dp[i][j-1][0][k]+G2*\lfloor \frac{sum-1}{2}\rfloor+G3\} dp[i][j][1][k+(sum−1 mod 2)]=1<=k<=cntmax{dp[i][j−1][0][k]+G2∗⌊2sum−1⌋+G3}
d p [ i ] [ j ] [ 1 ] [ k + ( s u m − 2 m o d 2 ) ] = max 1 < = k < = c n t { d p [ i ] [ j − 1 ] [ 1 ] [ k ] + G 2 ∗ ⌊ s u m − 2 2 ⌋ + G 3 } dp[i][j][1][k+(sum-2\ mod\ 2)]=\max_{1<=k<=cnt}\{ dp[i][j-1][1][k]+G2*\lfloor \frac{sum-2}{2}\rfloor+G3\} dp[i][j][1][k+(sum−2 mod 2)]=1<=k<=cntmax{dp[i][j−1][1][k]+G2∗⌊2sum−2⌋+G3}
sum%2,即看该区间内的"."的数量是不是奇数,如果是奇数,既有一个空位,否则没有。
此时dp部分得以解决。时间复杂度为
O
(
c
n
t
3
)
O(cnt^3)
O(cnt3)
我们在序列的最后加一个井号,最后答案在dp[cnt][p][0][c](0<=c<=cnt, 0<=p<=cnt)中求解产生,我们贪心的都取G1或者G2。
a
n
s
1
=
max
0
<
=
c
<
=
c
n
t
,
0
<
=
p
<
=
c
n
t
{
d
p
[
c
n
t
]
[
p
]
[
0
]
[
c
]
+
G
1
∗
m
i
n
(
c
,
K
)
+
G
1
∗
v
a
l
−
G
2
∗
⌈
v
a
l
2
⌉
}
ans1=\max_{0<=c<=cnt, 0<=p<=cnt}\{ dp[cnt][p][0][c]+G1*min(c,K)+G1*val-G2*\lceil\frac{val}{2}\rceil\}
ans1=0<=c<=cnt,0<=p<=cntmax{dp[cnt][p][0][c]+G1∗min(c,K)+G1∗val−G2∗⌈2val⌉}
如果min(la, sump)为奇数,答案还有:
a
n
s
2
=
max
0
<
=
c
<
=
c
n
t
,
0
<
=
p
<
=
c
n
t
{
d
p
[
c
n
t
]
[
p
]
[
0
]
[
c
]
+
G
1
∗
m
i
n
(
c
,
K
)
+
G
1
∗
(
v
a
l
−
1
)
−
G
2
∗
⌈
v
a
l
−
1
2
⌉
}
ans2=\max_{0<=c<=cnt, 0<=p<=cnt}\{ dp[cnt][p][0][c]+G1*min(c,K)+G1*(val-1)-G2*\lceil\frac{val-1}{2}\rceil\}
ans2=0<=c<=cnt,0<=p<=cntmax{dp[cnt][p][0][c]+G1∗min(c,K)+G1∗(val−1)−G2∗⌈2val−1⌉}
最后答案为:
a
n
s
=
m
a
x
(
a
n
s
1
,
a
n
s
2
,
max
0
<
=
c
<
=
c
n
t
,
0
<
=
p
<
=
c
n
t
{
d
p
[
c
n
t
]
[
p
]
[
0
]
[
c
]
+
G
1
∗
m
i
n
(
c
,
K
)
}
)
ans = max(ans1, ans2,\max_{0<=c<=cnt, 0<=p<=cnt}\{ dp[cnt][p][0][c]+G1*min(c,K)\})
ans=max(ans1,ans2,0<=c<=cnt,0<=p<=cntmax{dp[cnt][p][0][c]+G1∗min(c,K)})
其中:
l
a
=
k
−
m
i
n
(
c
,
K
)
,
v
a
l
=
m
i
n
(
l
a
,
s
u
m
p
)
la=k - min(c, K), val=min(la, sump)
la=k−min(c,K),val=min(la,sump)
之所有有ans2,是因为,我们如果将奇数个"."替换为G1,就会导致出现一个空位无法用G2覆盖,无法判定是不是更优的,(当然可以直接通过判G1,G2的大小得知,但是我懒得判了)
所有找解的复杂度为
O
(
c
n
t
2
)
O(cnt^2)
O(cnt2),最终复杂度为
O
(
c
n
t
3
)
O(cnt^3)
O(cnt3)
下面是ac代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include <map>
#include <queue>
#include <set>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <vector>
#include <string>
#include <list>
#include <bitset>
#include <array>
#include <cctype>
#include <time.h>
#pragma GCC optimize(2)
void read_f() { freopen("1.in", "r", stdin); freopen("1.out", "w", stdout);}
void fast_cin() { std::ios::sync_with_stdio(false); std::cin.tie(); }
void run_time() { std::cout << "ESC in : " << clock() * 1000.0 / CLOCKS_PER_SEC << "ms" << std::endl; }
#define ll long long
#define ull unsigned ll
#define _min(x, y) ((x)>(y)?(y):(x))
#define _max(x, y) ((x)>(y)?(x):(y))
#define max3(x, y, z) ( max( (x), max( (y), (z) ) ) )
#define min3(x, y, z) ( min( (x), min( (y), (z) ) ) )
#define pr(x, y) (make_pair((x), (y)))
#define pb(x) push_back(x);
using namespace std;
const int N = 1e5+5;
const int mod = 1e9+7;
const int inf = 0x3f3f3f3f;
int pos[N], cnt;
ll dp[64][64][2][128];
char su[N];
int main()
{
ll n, k, g1, g2, g3;
scanf("%lld%lld%lld%lld%lld", &n, &k, &g1, &g2, &g3);
memset(dp, 0x80808080, sizeof(dp));
scanf("%s", su+1);
for (int i = 1; i <= n; i++)
if (su[i] == '#') pos[++cnt] = i;
pos[++cnt] = n + 1;
dp[0][0][0][0] = 0;
for (int i = 1; i <= cnt; i++)
{
ll c = pos[i] - pos[i-1] - 1;
// cout << c << endl;
for (int j = 0; j <= cnt; j++)
{
for (int k = 0; k <= cnt; k++)
{
dp[i][j][0][k + (c & 1)] = max( dp[i][j][0][k + (c & 1)] , dp[i-1][j][0][k] + (c >> 1) * g2);
if (c >= 1)
{
dp[i][j][0][k + ((c-1) & 1)] = max( dp[i][j][0][k + ((c-1) & 1)] , dp[i-1][j][1][k] + ((c-1) >> 1) * g2);
if (j >= 1
dp[i][j][1][k + ((c-1) & 1)] = max( dp[i][j][1][k + ((c-1) & 1)] , dp[i-1][j-1][0][k] + ((c-1) >> 1) * g2 + g3);
}
if (c >= 2 && j >= 1)
{
dp[i][j][1][k + ((c-2) & 1)] = max( dp[i][j][1][k + ((c-2) & 1)] , dp[i-1][j-1][1][k] + ((c-2) >> 1) * g2 + g3);
}
}
}
}
ll ans = 0;
for (int p= 0; p <= cnt; p++)
{
for (int c = 0; c <= cnt; c++)
{
ll val = dp[cnt][p][0][c];
val += min(1ll * c, k) * g1;
ll la = k - min(1ll * c, k);
if (la && n - p*3 - c - (cnt - 1 - p) >= 0)
{
ll po = n - p*3 - c - (cnt - 1 - p);
val = max3(val, val + min(la, po) * g1 - (min(la, po) + 1) / 2 * g2, val + (min(la, po)&~1) * g1 - ((min(la, po)&~1) + 1) / 2 * g2 );
}
ans = max(ans, val);
}
}
printf("%lld\n", ans);
return 0;
}