题目分析
根据题目的意思,我们是需要检查在范围[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
risky′jobs′planned时间区间的重合数量,于是就有了如下代码:
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;
}