D. Robert Hood and Mrs Hood题解

题目链接

题目分析

根据题目的意思,我们是需要检查在范围[1,n−d+1]内所有可能起始日,并找出满足需求的起始日(即和brother的重合数最多,和mother重合时间最少);

暴力想法

一开始我的想法就是枚举每一个可能的左区间x,并且计算以该点为左区间的整个区间[x,x+d-1](注意这里是x+d-1!因为是在第x天开始持续d天,所以结束是第x+d-1天) k k k r i s k y ′ j o b s ′ p l a n n e d risky 'jobs' planned riskyjobsplanned时间区间的重合数量,于是就有了如下代码:

    int t;
    cin >> t;
    while (t--)
    {

        int n, d, k;
        cin >> n >> d >> k;

        vector<PII> wk;
        while (k--)
        {
            int l, r;
            cin >> l >> r;
            wk.push_back({l, r});
        }

        int mx = 0, ml = 1;
        int mn = 0x3f3f3f3f, mml = 1;
        for (int x = 1; x <= n - d + 1; x++)
        {
            int res = 0, res1 = 0;
            for (auto i : wk)
            	// 当x=>l[i]-d+1并且x<=r[i]的时候,这两个区间就是重叠的,可以画个图想想为什么;
            	// (好吧其实是因为当x==l[i]-d+1的时候以x为左端点的区间的右端点刚好和l[i]重合,符合条件;
                if (x >= i.first - d + 1 && x <= i.second)
                    res++, res1++;
            if (res > mx)
                mx = res, ml = x;
            if (res1 < mn)
                mn = res1, mml = x;
        }
        cout << ml << " " << mml << endl;
    }

优化

当我满心欢喜的提交代码的时候~Time limit exceeded on test 3 ~,来分析下为什么:每次我们在找到一个新的左区间端点x的时候都需要重新遍历来计算一次一共有几个区间和[x,x+d-1]有交集;
那么有没有什么办法能快速计算出区间[x,x+d-1]与几个区间有交集呢,这里提供了一个思路:==>用前缀和分别存储左区间端点和右区间端点,枚举变化区间的右端点x,那么交集的个数就是 ss[x] - es[x - d],这个很容易想明白为什么

#include <iostream>
#include <vector>
using namespace std;
typedef long long ll;
int main()
{
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    freopen("in", "r", stdin);
    int t;
    cin >> t;
    while (t--)
    {

        int n, d, k;
        cin >> n >> d >> k;
        int most = 0, least = 0x3f3f3f3f;
        int mstl = 1, lstl = 1;

        vector<int> ss(n + 1), es(n + 1);
        while (k--)
        {
            int a, b;
            cin >> a >> b;
            ss[a]++;
            es[b]++;
        }

        for (int i = 1; i <= n; i++)
            ss[i] += ss[i - 1], es[i] += es[i - 1];

        for (int x = d; x <= n; x++)
        {
            int cur = ss[x] - es[x - d];
            if (cur > most)
                most = cur, mstl = x - d + 1;
            if (cur < least)
                least = cur, lstl = x - d + 1;
        }

        cout << mstl << ' ' << lstl << endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值