题目大意
有一数轴,数轴上有
n
+
1
n+1
n+1个点,分别是
0
,
1
,
2
,
⋯
,
n
0,1,2,\cdots,n
0,1,2,⋯,n。
现在用从
0
0
0往
n
n
n铺水管,水管的高度只能为
1
1
1或
2
2
2。
在每一个点
(
0
,
1
,
2
,
⋯
,
n
)
\pod{0,1,2,\cdots,n}
(0,1,2,⋯,n)上,需要柱子支撑水管。
水管高度发生改变的位置为
1
2
,
3
2
,
⋯
,
2
×
n
−
1
2
\frac{1}{2},\frac{3}{2},\cdots,\frac{2\times n - 1}{2}
21,23,⋯,22×n−1。
由于某些原有,题目要求在某一些段上,水管的高度必须为
2
2
2,左右两端的高度必须为
1
1
1。
建造单位长度的水管需要花费
a
a
a,建造单位长度的柱子需要
b
b
b
问最小的建造代价。
时间限制
2s
数据范围
n ≤ 2 × 1 0 5 n \le 2 \times 10 ^ 5 n≤2×105
题解
很显然,这题就是个DP。
设
f
i
,
0
/
1
f_{i,0/1}
fi,0/1表示在第
i
i
i个点,水管高度为
1
1
1或者
2
2
2的最小花费。
转移是
O
(
1
)
O(1)
O(1)的。
同样高度的转移水管的花费为
a
a
a,不同高度之间的转移水管花费为
2
×
a
2\times a
2×a。
注意事项
要区分点和段。
题目在给出水管高度的要求时,是以段给出的,而DP方程中是以点来设置状态的。
对于不存在的状态,需要特殊标记一下。
另一种解法
其实这题也可以贪心。
水管在没有任何要求的情况下,显然是高度为
1
1
1最优。
在两个约束之间,判断多建造一些柱子的花费多还是多建造一些水管的花费多。
Code
//#pragma GCC optimize (2)
//#pragma G++ optimize (2)
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
#include <vector>
#include <queue>
#define G getchar
#define ll long long
using namespace std;
int read()
{
char ch;
for(ch = G();(ch < '0' || ch > '9') && ch != '-';ch = G());
int n = 0 , w;
if (ch == '-')
{
w = -1;
ch = G();
} else w = 1;
for(;'0' <= ch && ch <= '9';ch = G())n = (n<<1)+(n<<3)+ch-48;
return n * w;
}
const int N = 200005;
int n;
ll f[N][2] , a , b , mx;
char s[N];
int main()
{
//freopen("j.in","r",stdin);
//freopen("l.out","w",stdout);
for (int T = read() ; T ; T--)
{
n = read();
a = read();
b = read();
f[0][0] = b;
f[0][1] = -1;
scanf("%s" , s);
s[n] = '0';
for (int i = 1 ; i <= n ; i++)
{
if (s[i - 1] == '0' && s[i] == '0')
{
if (f[i - 1][0] == -1)
{
f[i][0] = f[i - 1][1] + 2 * a + b;
f[i][1] = f[i - 1][1] + a + 2 * b;
}else
if (f[i - 1][1] == -1)
{
f[i][0] = f[i - 1][0] + a + b;
f[i][1] = f[i - 1][0] + 2 * a + 2 * b;
}
else
{
f[i][0] = min (f[i - 1][1] + 2 * a + b , f[i - 1][0] + a + b);
f[i][1] = min (f[i - 1][1] + a + 2 * b , f[i - 1][0] + 2 * a + 2 * b);
}
}
else
{
f[i][0] = -1;
if (f[i - 1][0] == -1) f[i][1] = f[i - 1][1] + 2 * b + a; else
if (f[i - 1][1] == -1) f[i][1] = f[i - 1][0] + 2 * b +2 * a; else
f[i][1] = min(f[i - 1][1] + 2 * b + a , f[i - 1][0] + 2 * b +2 * a);
}
}
printf("%lld\n", f[n][0]);
}
return 0;
}