Educational Codeforces Round 71 (Rated for Div. 2) C. Gas Pipeline

87 篇文章 0 订阅
49 篇文章 0 订阅

题目大意

有一数轴,数轴上有 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×n1
由于某些原有,题目要求在某一些段上,水管的高度必须为 2 2 2,左右两端的高度必须为 1 1 1

建造单位长度的水管需要花费 a a a,建造单位长度的柱子需要 b b b
问最小的建造代价。

时间限制

2s

数据范围

n ≤ 2 × 1 0 5 n \le 2 \times 10 ^ 5 n2×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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值