I. Path Planning
嗯,怎么说呢,一般二维图,数据不是很大的比如n*m*log级别允许的,如果一眼不是bfs,可以考虑结合一下二分
本题可知,只能向下或者向右,那么我们就像如果答案为x,那么一定会有一条0到x-1的路存在,
我们再想一条路肯定是先右再下,然后重复进行的,类似于一个楼梯的样子。
二分我们知道了,但是check里面如何判断才能配合二分呢,对于我们check的mid ,我们可以先按行排序再按列排序,然后按这个先行后列的顺序按我们的原图找0~mid-1的数,然后只看列是否满足即可,也就是上一个的列值小于等与目前的列值。
int n, m;
int a[N];
bool check(int mid)
{
int last = -1;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
if (a[(i - 1) * m + j] <= mid - 1)
{
if (j < last)
return false;
last = j;
}
}
}
return 1;
}
void solve()
{
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
cin >> a[(i - 1) * m + j];
}
}
int l = 0, r = n * m;
while (l < r)
{
int mid = l + r + 1 >> 1;
if (check(mid))
l = mid;
else
r = mid - 1;
}
cout << r << endl;
}
B. Base Station Construction
题意:就是跟你一堆区间,每个区间里面必选选一个点,问最小花费。
我们考虑从dp下手,定义 为代表前 i 个位置且第 i 个位置必选选的最小花费,
定义完成以后我们考虑如何转移,显然我们要选的哪个点 J 要满足 在 之间不包含完整的一个区间不然就漏掉了,转移方程那就是 我们知道了 j 的区间范围但是不能 n方的去转移,我们考虑用单调对列来维护 一下 ,那么问题就解决了,最后我们在n+1位置建一个单点区间,以便于我们不用循环最后一个区间来找最小值了。
struct node
{
int l, r;
bool operator<(const node &w) const
{
if (r != w.r)
return r < w.r;
return l < w.l;
}
} p[N];
int a[N], b[N], que[N];
void solve()
{
int n, m;
cin >> n;
vector<int> f(n + 10); // f[i]表示前i个位置且第i个位置必选的最小花费
for (int i = 1; i <= n; i++)
cin >> a[i];
a[++n] = 0;
cin >> m;
for (int i = 1; i <= m; i++)
{
int l, r;
cin >> l >> r;
p[i] = {l, r};
}
sort(p + 1, p + 1 + m);
priority_queue<PII> q;
for (int i = 1, j = 0, k = 0; i <= n; i++)
{
while (j <= m && p[j].r < i)
q.push({p[j].l, p[j].r}), j++;
if (q.size() && q.top().xx > k)
k = q.top().xx;
b[i] = k;
}
int hh = 0, tt = 0; // 一开始里面有个0,相当于第一个限制区间,前面没有限制区间,也就是可以选单点,提前push一个0
for (int i = 1; i <= n; i++)
{
int k = b[i];
while (hh <= tt && que[hh] < k)
hh++;
f[i] = f[que[hh]] + a[i];
cout << f[i] << endl;
while (hh <= tt && f[que[tt]] >= f[i])
tt--;
que[++tt] = i;
}
cout << f[n] << endl;
}