Codeforces Round #731 (Div. 3) E. Air Conditioners(思维/DP/二分/区间最值/好题)
On a strip of land of length 𝑛n there are 𝑘k air conditioners: the 𝑖i-th air conditioner is placed in cell 𝑎𝑖ai (1≤𝑎𝑖≤𝑛1≤ai≤n). Two or more air conditioners cannot be placed in the same cell (i.e. all 𝑎𝑖ai are distinct).
Each air conditioner is characterized by one parameter: temperature. The 𝑖i-th air conditioner is set to the temperature 𝑡𝑖ti.
Example of strip of length 𝑛=6n=6, where 𝑘=2k=2, 𝑎=[2,5]a=[2,5] and 𝑡=[14,16]t=[14,16].
For each cell 𝑖i (1≤𝑖≤𝑛1≤i≤n) find it's temperature, that can be calculated by the formula
min1≤𝑗≤𝑘(𝑡𝑗+|𝑎𝑗−𝑖|),min1≤j≤k(tj+|aj−i|),
where |𝑎𝑗−𝑖||aj−i| denotes absolute value of the difference 𝑎𝑗−𝑖aj−i.
In other words, the temperature in cell 𝑖i is equal to the minimum among the temperatures of air conditioners, increased by the distance from it to the cell 𝑖i.
Let's look at an example. Consider that 𝑛=6,𝑘=2n=6,k=2, the first air conditioner is placed in cell 𝑎1=2a1=2 and is set to the temperature 𝑡1=14t1=14 and the second air conditioner is placed in cell 𝑎2=5a2=5 and is set to the temperature 𝑡2=16t2=16. In that case temperatures in cells are:
- temperature in cell 11 is: min(14+|2−1|,16+|5−1|)=min(14+1,16+4)=min(15,20)=15min(14+|2−1|,16+|5−1|)=min(14+1,16+4)=min(15,20)=15;
- temperature in cell 22 is: min(14+|2−2|,16+|5−2|)=min(14+0,16+3)=min(14,19)=14min(14+|2−2|,16+|5−2|)=min(14+0,16+3)=min(14,19)=14;
- temperature in cell 33 is: min(14+|2−3|,16+|5−3|)=min(14+1,16+2)=min(15,18)=15min(14+|2−3|,16+|5−3|)=min(14+1,16+2)=min(15,18)=15;
- temperature in cell 44 is: min(14+|2−4|,16+|5−4|)=min(14+2,16+1)=min(16,17)=16min(14+|2−4|,16+|5−4|)=min(14+2,16+1)=min(16,17)=16;
- temperature in cell 55 is: min(14+|2−5|,16+|5−5|)=min(14+3,16+0)=min(17,16)=16min(14+|2−5|,16+|5−5|)=min(14+3,16+0)=min(17,16)=16;
- temperature in cell 66 is: min(14+|2−6|,16+|5−6|)=min(14+4,16+1)=min(18,17)=17min(14+|2−6|,16+|5−6|)=min(14+4,16+1)=min(18,17)=17.
For each cell from 11 to 𝑛n find the temperature in it.
大意就是有n个位置,其中有k个位置有空调,空调有两个参数ai和ti,ai表示其所在的位置,ti表示其本身温度,然后对于每个位置求出其最小的温度(\(min_{1<=j<=k}(t_j+|a_j - i|)\))。
这题大概有好多种做法,最简单的是执行一遍类似dp的过程,正着更新一遍再反着更新一遍取最小,正确性显然(但就是没想到):
#include <bits/stdc++.h>
using namespace std;
int n, k, ans[300005];
int a[300005], t[300005];
int main() {
int q;
cin >> q;
for(int i = 1; i <= q; i++) {
cin >> n >> k;
for(int j = 1; j <= n; j++) {
ans[j] = 0x3f3f3f3f;
}
for(int j = 1; j <= k; j++) {
cin >> a[j];
}
for(int j = 1; j <= k; j++) {
cin >> t[j];
ans[a[j]] = t[j];
}
for(int i = 2; i <= n; i++) {
ans[i] = min(ans[i], ans[i - 1] + 1);
}
for(int i = n - 1; i >= 1; i--) {
ans[i] = min(ans[i], ans[i + 1] + 1);
}
for(int i = 1; i <= n; i++) {
cout << ans[i] << " ";
}
cout << endl;
}
return 0;
}
由于我是脑瘫,只能想到没十年脑溢血想不到的做法:首先去绝对值,可以发现实际上是\(min(min_{1<=j<i}(t_j+i-a_j), min(_{i<=j<=k}(t_j+a_j-i))\)
因此先把输入的空调按a从小到大排序(后面二分会用到),然后预处理每个空调的t+a以及t-a存入数组,遍历每个位置,首先查找这个位置左右两边的空调的分界点在哪里,然后分别查询左右两边的区间最值,再分别+i、-以后求min即可。查询静态区间最值可以用RMQ算法。
#include <bits/stdc++.h>
using namespace std;
int n, k, ans[300005];
int a[300005], t[300005];
int f1[300005], f2[300005];
#define MAX 300005
int Min_dp1[MAX][100];
int Min_dp2[MAX][100];
struct node {
int a, t;
} nd[300005];//仅用来给a排序 没啥用
bool cmp (node a, node b) {
return a.a < b.a;
}
void RMQ1(int num)
{
//建立动态表
for(int i= 1; i <= num; i++) {
Min_dp1[i][0] = f1[i];
}
for(int j=1;(1<<j)<=num;j++)
{
for(int i=1;i+(1<<j)-1<=num;i++)
{
int m = i+(1<<(j-1));
Min_dp1[i][j] =min(Min_dp1[i][j-1],Min_dp1[m][j-1]);
}
}
}
int query1(int l,int r)
{
int len = r-l+1;
//C语言中log默认以e为底,所有除以log2
int m = (int)(log((double)len) / log(2.0));
int minn = min(Min_dp1[l][m],Min_dp1[r-(1<<m)+1][m]);
return minn;
}
void RMQ2(int num)
{
//建立动态表
for(int i= 1; i <= num; i++) {
Min_dp2[i][0] = f2[i];
}
for(int j=1;(1<<j)<=num;j++)
{
for(int i=1;i+(1<<j)-1<=num;i++)
{
int m = i+(1<<(j-1));
Min_dp2[i][j] =min(Min_dp2[i][j-1],Min_dp2[m][j-1]);
}
}
}
int query2(int l,int r)
{
int len = r-l+1;
//C语言中log默认以e为底,所有除以log2
int m = (int)(log((double)len) / log(2.0));
int minn = min(Min_dp2[l][m],Min_dp2[r-(1<<m)+1][m]);
return minn;
}
int main() {
int q;
cin >> q;
for(int i = 1; i <= q; i++) {
cin >> n >> k;
for(int j = 1; j <= k; j++) {
cin >> nd[j].a;
}
for(int j = 1; j <= k; j++) {
cin >> nd[j].t;
}
sort(nd + 1, nd + k + 1, cmp);
for(int j = 1; j <= k; j++) {
a[j] = nd[j].a;
}
for(int j = 1; j <= k; j++) {
t[j] = nd[j].t;
}
for(int j = 1; j <= k; j++) {
f1[j] = a[j] + t[j];
f2[j] = t[j] - a[j];
}
RMQ1(k);
RMQ2(k);
for(int i = 1; i <= n; i++) {
int pos1 = lower_bound(a + 1, a + k + 1, i) - a;
int pos2 = pos1 - 1;
//1 ~ pos1 查询f2的最小值再加i pos2 ~ n 查询f1的最小值 再减i 这两者取min
int ans = 0x3f3f3f3f;
if(pos2 >= 1 && pos2 <= k) ans = min(ans, query2(1, pos2) + i);
if(pos1 >= 1 && pos1 <= k) ans = min(ans, query1(pos1, k) - i);
cout << ans << " ";
}
cout << endl;
}
return 0;
}
看别人的代码还有用优先队列做的,不明觉厉