首页 > 其他分享 >牛吃草 题解

牛吃草 题解

时间:2024-02-22 11:37:10浏览次数:19  
标签:le 队列 题解 喂草 int 牛吃草 dp size

牛吃草

居然真的是牛吃草

Description

由于现代化进程的加快,农场的养殖业也趋向机械化。

lyz 决定购置若干台自动喂草机来减少自己每天的工作量。为了简化问题,lyz 决定将草地建模成一条线段,总长为 \(n\),即共有\(n\) 个单位长度,编号从左至右为 \(1∼n\)。

lyz 可以在每个单位长度独立选择是否放置一台自动喂草机。由于场地的限制,喂草机一旦在 \(i\) 处放下,它只能往左边延伸覆盖一个从 \(i\) 开始的完整区间,且延伸的距离不能超过 \(w_i\) ,即最多到编号为 \(i-w_i+1\) 的单位长度。同时为了小草的健康着想,营养不能太丰富,因此每个单位长度只能被一台自动喂草机覆盖。

lyz 想使得每台喂草机的覆盖大小达到一个最低标准以节省费用,若喂草机覆盖 $ [l,r] $ ,那么覆盖大小为 \(r-l+1\) 。他规定一台喂草机最小覆盖大小为 \(size\) 。所以如果一台喂草机的覆盖大小\(< size\),说明这个位置不能放置喂草机。

现在,lyz 想知道,如果喂草机覆盖的总大小仅需达到草地总长的 \(s \%\),最小覆盖大小最大是多少?

Input

输入共三行。

第一行输入整数 n。

第二行输入n 个整数 \(w_i\) ,表示第 i个位置的延伸距离不能达到 \(w_i\)。

最后一行给定整数 s,意义如上述所示。

Output

输出最大的 size,意义如上述所示。

Samples

 4
 1 2 3 4
 100
 4

样例解释1

最小覆盖最大值就为 4,在第四个位置放喂草机即可。

 5
 5 4 2 3 2
 50
 3

样例解释2

在第四个位置放喂草机,可以覆盖 3 个位置,覆盖率达到 50% 以上。

数据范围

对于 100%的数据,$1\le s \le 100,2\le i\le n, w_{i-1}\ge w_i-1 $

正解

二分+单调队列优化DP

一眼就可以看出是二分答案 (所以半眼是看不出来的

注意审题,赛时一车人读假题目了,喂草机最大范围是 \(w_i\) ,可以小于这个值,因此最后结果不一定在 \(w_i\) 中取,另外二分左端点应该从1开始。

二分答案 size ,然后检查答案是否可行,求当前 size 最大的覆盖面积与 \(s\%\) 比较。check函数用DP实现。

朴素DP

令 \(f_i\) 为前 \(i\) 个草坪能覆盖的最大面积,对于 \(f_i\) 可能放也可能不放。

如果放置喂草机,对覆盖面积没有影响, $f_i=f_{i-1} $

如果不放,考虑可能的转移来源, \(i\) 的最大覆盖面积为 \(w_i\) ,转移的左端点应该是 $i-w_i $ ,又因为覆盖面积不能小于size,转移的右端点是 $i-size $ 。得到方程:

\[f_i= \max_{i-w_i \le j \le i-size} \{ f_j+i-j \} \]

单调队列优化

上述做法显然是会T的,考虑优化。

注意到数据范围中至关重要的一点

\[w_{i-1} \ge w_i-1 \]

这是解决整个题目的关键 (不知多少人没看见呢)

仔细想想 \(w_i\) 决定了DP转移区间的左端点,而上述条件保证的是这个左端点不会因 \(i\) 增大而减小,即左端点的下标单调不下降,自然而然想到单调队列。

调整一下方程

\[f_i= \max_{i-w_i \le j \le i-size } \{ (f_j-j)+i \} \]

对于 \(f_i\) ,方程中的 \(i\) 是一定的,用单调队列维护 $ f_j-j $

注意 \(f_j-j\) 进入单调队列的时间,并不是刚刚计算 \(f_j\) 就进队列,而是对于每一个可行的 \(i\) ,将 $ f_{i-x}-(i-x) $ 压入队列。

这样做是因为本题对转移的左右端点均有限制,直接 $ push _ back (f_j-j) $ 可能导致某些 $f_k(j<k<i) $ 右端点不符合要求

另外一点,如果双端队列在check函数里定义,一定要清空,否则队列里会有其他元素。

Code

#include<bits/stdc++.h>
using namespace std;
const int N=6e5;
int n,w[N],s,maxn,minn=1e8,dp[N],ans;
deque<int>q;
bool check(int x){
    memset(dp,0,sizeof(dp));
    int p=0;
    q.clear( ) ; 
    for(int i=1;i<=n;i++){
        if(i>=x){
            while(!q.empty()&&dp[i-x]-(i-x)+n>dp[q.back()]-q.back()+n)
            q.pop_back();
            q.push_back(i-x);
        }
        dp[i]=max(dp[i],dp[i-1]);
        while(!q.empty()&&i-q.front()>w[i])q.pop_front();
        if(!q.empty()) dp[i]=max(dp[q.front()]+(i-q.front()),dp[i]);
        p=max(p,dp[i]);
    }
    if(p>=((s*n+99)/100))return 1;
    else return 0;
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("1.in","r",stdin);
    freopen("1.out","w",stdout);
    #endif
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&w[i]);
        maxn=max(maxn,w[i]);
        minn=min(minn,w[i]);
    }
    scanf("%d",&s);
    int l=1,r=maxn;
    while(l<=r){
        int mid=(l+r)>>1;
        if(check(mid))l=mid+1;
        else r=mid-1;
    }
    printf("%d",r);
}

标签:le,队列,题解,喂草,int,牛吃草,dp,size
From: https://www.cnblogs.com/abnormal123/p/18026939

相关文章

  • blocks 单调栈、单调队列题解
    blocks题解:1、题面:2、分析:题意大概就是说,找一段最长的区间,并且这段区间的平均值>=k,那么我们可以对他的每一个值减去k,最终求和>=0即可。那我们需要对每个可能的左端点和右端点进行考虑,并以此让他们进行配对,看他们之间的区间和是否非负。那么我们先定住一个右端点,再依次考虑......
  • 理想的正方形 题解
    题目描述有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小。输入格式第一行为3个整数,分别表示a,b,n的值第二行至第a+1行每行为b个非负整数,表示矩阵中相应位置上的数。每行相邻两数之间用一空格分隔。100%的数据2<......
  • P5344 【XR-1】逛森林 题解
    题目链接:逛森林很早就想写写倍增优化建图,尤其是这题,奈何之前知识点没点够,本题线段树优化建图要优一些,不再赘述,没注意\(m\)是\(1e6\),挂了\(n\)多发才发现。后续再详细讲解倍增优化建图,这里简述本题做法。倍增优化建图其实和线段树优化建图恰不多的思想,为倍增求\(LCA\)的每......
  • 2024年2月21号题解
    106.从中序与后序遍历序列构造二叉树力扣题目链接解题思路找到根节点在中序序列的位置计算左子树的节点个数开辟一个节点,并把根节点的值赋值给这个节点根节点的左孩子和右孩子重复上面几个步骤代码实现/***Definitionforabinarytreenode.*structTreeNode{......
  • Day-7 模拟赛题解
    Day-7模拟赛题解S+N---【玄英计划】---2月21日---模拟测#3【补题】-比赛-梦熊联盟T1数据点3-5枚举每一个问号对应的字母Kmp,把s当作模式串匹配T\(O(26^k|T|)\),k是?的个数代码(我也不知道为啥T了,鸽着)正解有种被诈骗了的感觉根据期望的可加性,答案等于......
  • P10064 [SNOI2024] 公交线路 题解
    非常好题目。思路可以发现限制最严的一定是两个叶子的联通性。我们不妨把一个叶子向外起到联通性作用的路径称为有用的路径。也就是这个叶子走这条路径一定可以两步以内到达任意点。这个路径集合有什么作用呢。有一个性质:整个集合的路径的交最终会形成一个连通块。那么我们......
  • Atm/抢掠计划——题解
    题目描述样例671223352441266510128161514435647解析题目明显是最长路,可以用spfa求最长路,但数据范围5e5明显不允许,所以我们可以用tarjan优化一下,然后这就变成了一道tarjan板子题,先用tarjan缩点,点权为几个点之和,把所有点再存到一个数组中,再按......
  • 初三年后集训测试 T2--牛吃草
    初三年后集训测试$T2$牛吃草一言难尽$$HZOI$$$Description$由于现代化进程的加快,农场的养殖业也趋向机械化。\(QZS\)决定购置若干台自动喂草机来减少自己每天的工作量。为了简化问题,\(QZS\)决定将草地建模成一条线段,总长为\(n\),即共有\(n\)个单位长度,编号从......
  • 洛谷P4447题解
    md这篇反正不交题解的,随便写,不管它格式题意简化下,给你N个数,求出连续值分组人数最小的那组的人数最大值。这个题目还挺经典的,原本23年8月份过了到现在来又不会了(划掉,bushi对于这种,很容易想到的是输入,之后排序,然后分组这种模板就不多说了,就在我24年2月份重温这道题再打一遍代码......
  • 1 c++算法题解析-两个数之和
    //给定一个整数数组nums和一个整数目标值target,请你在该数组中找出和为目标值target的那两个整数,并返回它们的数组下标。//你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。//你可以按任意顺序返回答案。//示例1:////输入:nums=[2,7,......