usaco2018 feb cu Taming the Herd

本文探讨了USACO竞赛中的一道经典题目——奶农John如何通过不完整的记录来判断奶牛出逃的最小和最大次数。文章详细解析了解题思路和关键步骤,并提供了一段C++实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://www.elijahqi.win/2018/03/03/usaco2018-feb-cu-taming-the-herd/
Early in the morning, Farmer John woke up to the sound of splintering wood. It was the cows, and they were breaking out of the barn again!

Farmer John was sick and tired of the cows’ morning breakouts, and he decided enough was enough: it was time to get tough. He nailed to the barn wall a counter tracking the number of days since the last breakout. So if a breakout occurred in the morning, the counter would be 0

0

that day; if the most recent breakout was 3

3

days ago, the counter would read 3

3

. Farmer John meticulously logged the counter every day.

The end of the year has come, and Farmer John is ready to do some accounting. The cows will pay, he says! But lo and behold, some entries of his log are missing!

Farmer John is confident that the he started his log on the day of a breakout. Please help him determine, out of all sequences of events consistent with the log entries that remain, the minimum and maximum number of breakouts that may have take place over the course of the logged time.

INPUT FORMAT (file taming.in):

The first line contains a single integer N

N
(1≤N≤100

1≤N≤100
), denoting the number of days since Farmer John started logging the cow breakout counter.The second line contains N

N
space-separated integers. The i

i
th integer is either −1

−1
, indicating that the log entry for day i

i
is missing, or a non-negative integer ai

ai
(at most 100

100
), indicating that on day i

i
the counter was at ai

ai
.

OUTPUT FORMAT (file taming.out):

If there is no sequence of events consistent with Farmer John’s partial log and his knowledge that the cows definitely broke out of the barn on the morning of day 1

1
, output a single integer −1

−1
. Otherwise, output two space-separated integers m

m
followed by M

M
, where m

m
is the minimum number of breakouts of any consistent sequence of events, and M

M
is the maximum.

SAMPLE INPUT:

4
-1 -1 -1 1
SAMPLE OUTPUT:

2 3
In this example, we can deduce that a breakout had to occur on day 3. Knowing that a breakout also occurred on day 1, the only remaining bit of uncertainty is whether a breakout occurred on day 2. Hence, there were between 2 and 3 breakouts in total.

Problem credits: Dhruv Rohatgi

-1代表当天数据丢失 如果牛出逃则计数器变成0 否则计数器显示的是距离上一次牛出逃

现在给一个计数器的序列 求牛最多和最少出逃几次

贪心 中间有-1 全部都认为出逃或者都不出逃 注意好边界条件即可

#include<cmath>
#include<cstdio>
#include<algorithm>
#define N 110
using namespace std;
inline char gc(){
    static char now[1<<16],*S,*T;
    if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while(ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=gc();}
    while(ch<='9'&&ch>='0') x=x*10+ch-'0',ch=gc();
    return x*f;
}
int ans1;//-1's num
int ans2,n,x[N];// mininum times
bool visit[N];
int main(){
    freopen("taming.in","r",stdin);
    freopen("taming.out","w",stdout);
    n=read();bool flag=0;ans2=1;
    for (int i=1;i<=n;++i) x[i]=read();
    for (int i=n;i;--i){
         if (visit[i]) continue;
         if (x[i]==-1){if (i!=1)++ans1;continue;}
         int now=x[i];++ans2;
         for (int j=0;j<=x[i];++j,--now){
            if (i-j<0) {flag=1;break;}
            visit[i-j]=1;
            if (x[i-j]!=now&&x[i-j]!=-1) {flag=1;break;}
            if (i-j==1) --ans2;
         }
    }
    if (flag) {puts("-1");return 0;}
    printf("%d %d",ans2,ans2+ans1);
    return 0;
}
### 解题思路 此问题的核心在于通过 **二维差分** 和 **前缀和** 的方法来高效计算被指定层数 $ K $ 涂漆覆盖的区域大小。以下是详细的分析: #### 1. 题目背景 农夫约翰希望在他的谷仓上涂油漆,目标是找到最终被恰好 $ K $ 层油漆覆盖的总面积。给定若干矩形区域及其对应的涂漆操作,我们需要统计这些操作完成后满足条件的区域。 #### 2. 差分法的应用 为了快速更新多个连续单元格的状态并查询其总和,可以采用 **二维差分** 技术。具体来说: - 初始化一个二维数组 `diff` 来表示差分矩阵。 - 对于每一个矩形 $(x_1, y_1)$ 到 $(x_2, y_2)$,我们可以通过如下方式更新差分矩阵: ```python diff[x1][y1] += 1 diff[x1][y2 + 1] -= 1 diff[x2 + 1][y1] -= 1 diff[x2 + 1][y2 + 1] += 1 ``` 上述操作的时间复杂度仅为常数级别 $ O(1) $,因此非常适合大规模数据集的操作[^1]。 #### 3. 前缀和恢复原矩阵 完成所有矩形的差分更新后,利用前缀和算法还原实际的涂漆次数矩阵 `paints`。对于每个位置 $(i,j)$,执行以下操作: ```python for i in range(1, n + 1): for j in range(1, m + 1): paints[i][j] = (paints[i - 1][j] + paints[i][j - 1] - paints[i - 1][j - 1] + diff[i][j]) ``` 这里需要注意边界条件以及初始值设置为零的情况[^4]。 #### 4. 统计符合条件的区域 最后遍历整个 `paints` 数组,累加那些等于 $ K $ 的元素数量即可得到答案。 --- ### 实现代码 下面是基于以上理论的一个 Python 实现版本: ```python def painting_the_barn(): import sys input_data = sys.stdin.read().splitlines() N, K = map(int, input_data[0].split()) max_x, max_y = 0, 0 rectangles = [] for line in input_data[1:]: x1, y1, x2, y2 = map(int, line.split()) rectangles.append((x1, y1, x2, y2)) max_x = max(max_x, x2) max_y = max(max_y, y2) # Initialize difference array with extra padding to avoid boundary checks. size = max(max_x, max_y) + 2 diff = [[0]*size for _ in range(size)] # Apply all rectangle updates using the difference method. for rect in rectangles: x1, y1, x2, y2 = rect diff[x1][y1] += 1 diff[x1][y2 + 1] -= 1 diff[x2 + 1][y1] -= 1 diff[x2 + 1][y2 + 1] += 1 # Compute prefix sums from differences to get actual paint counts. paints = [[0]*size for _ in range(size)] result = 0 for i in range(1, size): for j in range(1, size): paints[i][j] = ( diff[i][j] + paints[i - 1][j] + paints[i][j - 1] - paints[i - 1][j - 1] ) if paints[i][j] == K: result += 1 return result print(painting_the_barn()) # Output final answer as per sample output format. ``` --- ### 结果验证 按照样例输入测试该程序能够正确返回预期的结果即8单位面积被两层涂料所覆盖[^2]。 --- ### 性能优化建议 如果进一步追求效率还可以考虑压缩坐标范围减少内存消耗或者使用更底层的语言实现核心逻辑部分比如 C++ 或 Java 等[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值