15006:社交距离I(题目+分析+代码)

新出的题,在ybt拓展题库(点此处进入

题目(点此处进入

15006:社交距离I

时间限制: 1000 ms         内存限制: 131072 KB
提交数: 4     通过数: 2
【题目描述】
一种新型疾病,COWVID-19,开始在全世界的奶牛之间传播。Farmer John 正在采取尽可能多的预防措施来防止他的牛群被感染。

Farmer John 的牛棚是一个狭长的建筑物,有一排共 N
 个牛栏(2≤N≤105
)。有些牛栏里目前有奶牛,有些目前空着。得知“社交距离”的重要性,Farmer John 希望使得D
 尽可能大,其中 D
 为最近的两个有奶牛的牛栏的距离。例如,如果牛栏 3
和8
 是最近的有奶牛的牛栏,那么 D=5
。

最近两头奶牛新来到 Farmer John 的牛群,他需要决定将她们分配到哪两个之前空着的牛栏。请求出他如何放置这两头新来的奶牛,使得 D
 仍然尽可能大。Farmer John 不能移动任何已有的奶牛;他只想要给新来的奶牛分配牛栏。

【输入】
输入的第一行包含 N
。下一行包含一个长为 N
 的字符串,由 0
 和 1
 组成,描述牛棚里的牛栏。0
 表示空着的牛栏,1
 表示有奶牛的牛栏。字符串中包含至少两个 0
,所以有至少有足够的空间安置两头新来的奶牛。

【输出】
输出 Farmer John 以最优方案在加入两头新来的奶牛后可以达到的最大 D
 值(最近的有奶牛的牛栏之间的距离)。

【输入样例】
14
10001001000010
【输出样例】
2
【提示】
在这个例子中,Farmer John 可以以这样的方式加入奶牛,使得牛栏分配变为 10x010010x0010,其中 x 表示新来的奶牛。此时 D=2
。不可能在加入奶牛之后取到更大的 D
 值。

【测试数据范围】

测试点 2-6 满足 N≤10
。

测试点 7-8 满 N≤100
。

测试点 9-11 满足 N≤5000
。

测试点 12-15 没有额外限制。

分析

  这个问题可以通过寻找初始状态下所有相邻的奶牛之间最大的空牛栏间隔,然后在这些间隔中找到一个合适的位置放入两头新奶牛,以最大化这个间隔。关键在于找出最大的空区间,并且考虑新牛如何能最有效地增加这个最大间隔。具体算法步骤如下:
    1. 找到所有现有奶牛之间的空区间,包括最左边和最右边的空区间(如果有),记录每个区间的长度。
    2. 为了最大化社交距离,我们优先考虑最长的空区间,因为这里放入新奶牛能带来最大的间隔增加。
    3. 但是,我们需要考虑边界情况:假设最长的空区间为 L,如果我们将两头新牛放入这个区间,那么这个区间的距离将被分成两部分。为了使整体社交距离最大化,我们应该尽量使这两部分接近,即分别在该区间的中间位置左右各放入一头牛。如果 L 是奇数,那么分割后两边的间隔相同;如果 L 是偶数,则两边间隔差值为1。
    4. 我们还需要考虑的是,如果存在多个相同长度的最大空区间,我们选择两端的区间放置新牛,以避免减少其他区间的社交距离。对于输入样例:
14
10001001000010
󠁪  首先,我们可以看到最长的空区间是 0000󠁪(长度为4),位于字符串的中间。如果我们在中间位置插入两头新牛,即在第5位和第9位,那么我们将得到:10x010010x0010
 󠁪 其中,x󠁪 表示新来的奶牛。现在,最长的间隔是 00󠁪 或 0x0󠁪(长度为2),这比原来没有新牛时的最长间隔 0000󠁪(长度为4)更短,但这是在保持最大社交距离前提下的最优解。因此,输出为:
2
 󠁪 实现这个算法的关键是在遍历输入字符串的过程中,正确地识别和记录所有空区间,并在最后根据上述逻辑确定最优的放置策略

代码

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n;
char s[N];
int res=1e9;
vector<int> heap;
int find(int x)
{
    return lower_bound(heap.begin(),heap.end(),x)-heap.begin();
}

bool check(int x)
{
    if(x>=n) return false;
    vector<int> q;
    vector<int> copy=heap;
    for(int i=0;i<n;i++)
    {
        if(s[i]=='0')
        {
            int a=heap[find(i)],b=heap[find(i)-1];
            if(a-i >= x and i-b >=x) 
            {
                q.push_back(i);
                heap.push_back(i);
                sort(heap.begin(),heap.end());
                s[i]='1';
                break;                
            }
        }
    }
    if(q.size()==0) return false;
    for(int i=n-1;i>=0;i--)
    {
        if(s[i]=='0')
        {
            int a=heap[find(i)],b=heap[find(i)-1];
            if(a-i >= x and i-b >=x) 
            {
                q.push_back(i);
                s[i]='1';
                break;                
            }
        }
    }
    heap=copy;
    for(auto t:q) s[t]='0';
    if(q.size()<2) 
    {
        return false;
    }
    return true;
}

signed main()
{
    cin>>n;
    cin>>s;
    heap.push_back(-1e9);
    int last=-1;
    for(int i=0;i<n;i++) 
    {
        if(s[i]=='1') 
        {
            if(last==-1) last=i;
            else res=min(res,i-last),last=i;
            heap.push_back(i);
        }
    }
    heap.push_back(1e9);
    int l=1,r=n;
    while(l<r)
    {
        int mid=l+r+1>>1;
        if(check(mid)) l=mid;
        else r=mid-1;
    }
    cout<<min(res,r);
}

要点

  1. 扫描序列并记录空区间:
    • 遍历整个序列,识别所有连续的空牛栏(0)形成的区间,并记录它们的起始位置和长度。
    • 特别注意序列开头和结尾的空区间,因为它们可能与新加入的奶牛产生最大社交距离。
  2. 寻找最大空区间:
    • 在所有的空区间中找到最长的那个(或几个,如果有多个等长的)。
    • 最长的空区间是放置新奶牛的最佳候选区域,因为它提供了最大的间隔潜力。
  3. 确定新牛的放置策略:
    • 如果最长的空区间长度为偶数,放置新牛使得该区间被均匀分割,确保社交距离最大化。
    • 如果为空奇数,则新牛放置后,将该区间分割为一个较小的偶数区间和一个较小的奇数区间,仍追求最大间隔。
  4. 处理多个最大空区间的情况:
    • 如果存在多个相同长度的最大空区间,优先考虑放置新牛在序列的两端,以避免减少其他区间的社交距离。
  5. 计算最终社交距离:
    • 根据新牛的放置策略,重新计算最大社交距离,作为输出结果。
摘要:整个算法的关键在于高效地扫描序列和决策新牛的放置,以优化社交距离。通过一次遍历即可完成空区间的识别和长度记录,然后在第二次遍历时做出最佳放置决策,确保算法的时间复杂度保持在可接受范围内,即使对于较大的序列也能快速得出结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值