只学习不思考不记笔记==假把式
这道题目的难度很难,当然主要的原因在于模型的转化,刚看的这道题也是一脸懵,但是转换成覆盖模型后就好了很多,归跟接地就是每块区域的中取最大的最少的牛覆盖天数,然后根据这个天数求每一块地的最少牛数。
首先要分三块地方去考虑问题。
1.最左边和最右边

在左右两边最少的牛的覆盖天数很明显就是一头就是最左边或者最右边一头牛感染了,然后传染给别人,然后我们可以得到两边的天数为(总牛的数-1);
天数等于总牛数-1
那么我们可以得到不等式:
总天数<=总牛数-1
2.中间
那么如果我们的牛在中间呢,最少的牛数怎么求。
这时候容易想到的是奇数的情况即:
两倍的天数+1=总牛数
即最开始只有中间一头牛然后向两边扩张
天数=(总牛数-1)/2
那么偶数情况其实就是
两倍的天数+2=总牛数
天数=(总牛数-2)/2
那么结合上面两个式子我们可以得到
天数<=(总牛数-1)/2;
那么对于我们想要我们每个区间的牛数最小就要我们的天数越大。
最后我们根据所有的牛数最小的最大天数中取最小值(这里因为如果天数取大了会导致感染不了这么多牛)。然后再对每个区间的牛做分配。
那么题目下面就转化成了天数一定,牛的感染总数一定的时候,如何让牛的起始数量最少。
那就很明显我们应该让我们的牛在中间即
牛数(2*天数+1)=区间总感染牛数
牛数=(区间总感染牛数)/(2*天数+1)
这里我们要进行向上取整,如果向下可能会导致覆盖不够
那么就要用我们的公式:
然后对式子做优化
牛数=(区间总感染牛数+2*天数)/2*天数+1
最终得到我们完整的代码
#include<vector>
#include<iostream>
using namespace std;
const int N=3e5+10;
char a[N];
int main()
{
int n;
cin>>n;
for(int i=0;i<n;i++)cin>>a[i];
vector<int>cnt;//存入每个区间牛最少时候的天数
int r=n;
for(int i=0;i<n;i++){
if(a[i]=='0')continue;
int j=i+1;
while(j<n&&a[j]=='1')j++;//遍历到1结束位置
int d=j-i, c=(d-1)/2;//d为牛数,c为中间区域的天数
if(!i||j==n)//左右边界情况
c=d-1;
r=min(r,c);//最小的天数
cnt.push_back(d);
i=j;
}
int res=0;
for(auto ch:cnt)
{
res+=(ch+2*r)/(2*r+1);//向上取整
}
cout<<res;
}