[USACO23DEC] Cowntact Tracing 2 B

 题目描述

Farmer John 有 N 头奶牛排成一列(1<=N<=3*10^5)。不幸的是,有一种疾病正在传播。

最初,有一些奶牛被感染。每到夜晚,被感染的奶牛会将疾病传播给它左右两边的奶牛(如果这些奶牛存在的话)。一旦奶牛被感染,她就会持续处于感染状态。

经过一些晚上,Farmer John 意识到情况已经失控,因此他对奶牛进行了检测以确定哪些奶牛感染了疾病。请找出最少有多少头奶牛最初可能感染了这种疾病。

输入格式

第一行为一个整数 N,即 Farmer John 拥有的奶牛数量。

接下来一行,包含长度为 N 的由 1 和 0 组成的位串。其中 1 表示一头被感染的奶牛,0 表示一头在经过若干晚之后仍未被感染的奶牛。

输出格式

输出一个整数,表示最少有多少头奶牛可能最初感染了这种疾病。

样例输入 1
5
11111

样例输出 1
1

样例输入 2
6
011101

 样例输出 2
4

样例解释 1

假设只有中间的奶牛最初被感染。那么,奶牛们将按以下顺序被感染:

- 第 0 晚:00100(第三只奶牛一开始被感染)
- 第 1 晚:01110(第二和第四只奶牛现在被感染了)
- 第 2 晚:11111(第一和第五只奶牛现在被感染了)
- 第 3 晚:11111(所有的奶牛都已经被感染了,没有新的奶牛被感染)
- ……

经过两个或更多的晚上,奶牛们的状态即与输入的状态相符。还有许多其他的初始状态和夜晚数量可能导致了输入的状态,例如:

- 第 0 晚:10001
- 第 1 晚:11011
- 第 2 晚:11111

或者:

- 第 0 晚:01001
- 第 1 晚:11111

或者:

- 第 0 晚:01000
- 第 1 晚:11100
- 第 2 晚:11110
- 第 3 晚:11111

所有这些初始状态中至少有一头奶牛被感染。

题目解析

#include <vector>
#include <iostream>
using namespace std;
vector<int> v;

int main() {
    int n; //奶牛总数
    string s; //最终感染情况
    cin >> n >> s;

    int pre = 0, suf = n - 1, cnt = 0, minDay = n + 1;
    //pre和suf分别表示前和后的位置,cnt表示计数,minDay先设置为最坏情况的值
    while (s[pre] == '1') {
        pre++;
        //cout <<"pre: "<< pre << endl; 
    }//从前往后
    while (suf > pre && s[suf] == '1') {
        suf--;
        //cout<<"suf: " << suf << endl;
    } //从后往前
    
    if (pre != 0) { //
        v.push_back(pre);
        minDay = min(minDay, pre - 1);
    }

    if (suf != n - 1) {
        v.push_back(n - 1 - suf);//最后一团奶牛数是n-1-suf
        minDay = min(minDay, n - 2 - suf);//minDay就是n-2-suf
    }


    for (int i = pre; i <= suf; i++) {
        if (s[i] == '1') cnt++;
        else if (s[i] == '0') {
            if (cnt > 0) {
                v.push_back(cnt);
                minDay = min(minDay, (cnt - 1) / 2);
            }
            cnt = 0;
        }
    }
    if (cnt > 0) {
        v.push_back(cnt);
        minDay = min(minDay, (cnt - 1) / 2);
    }

    int ans = 0;
    for (int i = 0; i < v.size(); i++) { //v.size()表示有多少团1
        int k = v[i] / (minDay * 2 + 1); //minDay * 2 + 1 表示1头感染的奶牛通过minDay最多感染多少奶牛
        if (v[i] % (minDay * 2 + 1)) k++; //计算当前向量元素 v[i] 对应的 0 的个数需要多少个初始 1 来覆盖
        //如果当前 v[i] 不能被 (minDay * 2 + 1) 整除,说明有剩余的 0 需要额外的一个 1 来覆盖
        ans += k;
    }
    cout << ans;
    return 0;
}

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
题目描述 有一个长度为 $n$ 的书架,每本书有一个高度 $h_i$。现在你可以进行以下两种操作: - 将一本书放在书架的最左边或最右边,花费为 $c_1$。 - 将一本高度为 $h_i$ 的书放在一本高度为 $h_j$ 的书的上面,花费为 $c_2$。 现在你需要将书架上的书按照高度从小到大排列,求最小花费。 输入格式 第一行包含三个整数 $n,c_1,c_2$。 第二行包含 $n$ 个整数 $h_i$。 输出格式 输出一个整数,表示最小花费。 数据范围 $1\leq n\leq 200,1\leq c_1,c_2\leq 10^9,1\leq h_i\leq 10^9$ 输入样例 5 1 2 3 1 4 2 5 输出样例 6 算法1 (动态规划) $O(n^2)$ 首先考虑一个朴素的 dp,设 $f_{i,j}$ 表示前 $i$ 本书已经排好序,第 $i+1$ 本书放在第 $j$ 个位置的最小花费。 状态转移方程为: $$ f_{i,j}=\min\{f_{i-1,k}+c_1\}+\begin{cases}&\text{if }h_{i+1}>h_j\\c_2&\text{otherwise}\end{cases} $$ 其中 $k$ 取遍 $1\sim i$,表示将第 $i+1$ 本书放在第 $k$ 个位置。 时间复杂度 $O(n^3)$ C++ 代码 算法2 (单调队列优化) $O(n^2)$ 考虑优化上述 dp,发现状态转移方程中的 $\min$ 操作可以用单调队列优化,具体来说,我们维护一个单调递增的队列 $q$,其中 $q_i$ 表示第 $i$ 个位置的最小花费,那么对于状态 $f_{i,j}$,我们只需要找到 $q$ 中第一个大于等于 $f_{i-1,k}+c_1$ 的位置 $p$,然后 $f_{i,j}=q_p+\begin{cases}&\text{if }h_{i+1}>h_j\\c_2&\text{otherwise}\end{cases}$。 时间复杂度 $O(n^2)$ C++ 代码

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值