Luogu 3620 数据备份 - Set
Solution
很显然, 最优情况肯定是相邻两个相连 。
然后模型就跟 Luogu1484 类似了。
把两个房子 看成一个坑 (参考 Luogu1484), 选取 $k$ 个不相邻的坑, 使得权值最小。
Luogu1484 则是 选取 至多 $k$ 个不相邻坑, 使得权值最大。
先考虑简单问题:
当$k= 1$时, 肯定是选择 最大 的$a[i]$
当$k= 2$时, 仅有两种情况 选 最大的 $a[i]$ 和 不相邻的 $a[j]$ 或者 $a[i+1]+a[i-1]$
我们先选了最大的$a[i]$
那么怎么样才能让下一个找到的最大的 $a[j]$ 是满足条件的解呢?
我们把 $a[i - 1]$ 和 $a[i + 1]$ 删去, 然后把 $a[i]$改为 $a[i + 1] + a[i - 1] - a[i]$,这样就满足了肯定不会 单独选到 $a[i + 1]或a[i-1]$。
并且我们若想要选$a[i+1]和a[i-1]$且不选$a[i]$ 只需要再选一次$a[i]$即可。
在$k$更大的情况下同样适用。
然后就用链表存储 $nxt$ 与 $pre$, $Set$ 维护 最大值/ 最小值。
Code
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<set> 5 #define rd read() 6 #define ll long long 7 using namespace std; 8 typedef pair<ll, int> P; 9 10 const int N = 1e5 + 5; 11 const ll inf = 1e10; 12 13 int n, k; 14 int nxt[N], pre[N]; 15 ll a[N], ans; 16 set<P> st; 17 18 int read() { 19 int X = 0, p = 1; char c = getchar(); 20 for (; c > '9' || c < '0'; c = getchar()) 21 if (c == '-') p = -1; 22 for (; c >= '0' && c <= '9'; c = getchar()) 23 X = X * 10 + c - '0'; 24 return X * p; 25 } 26 27 void del(int x) { 28 nxt[pre[x]] = nxt[x]; 29 pre[nxt[x]] = pre[x]; 30 } 31 32 int main() 33 { 34 n = rd; k = rd; 35 for (int i = 1; i <= n; ++i) 36 a[i] = rd; 37 n--; 38 for (int i = 1; i <= n; ++i) 39 a[i] = a[i + 1] - a[i]; 40 for (int i = 1; i <= n; ++i) 41 nxt[i] = i + 1, pre[i] = i - 1; 42 for (int i = 1; i <= n; ++i) 43 st.insert(P(a[i], i)); 44 a[0] = a[n + 1] = inf; 45 set<P> :: iterator it; 46 for (; k; --k) { 47 it = st.begin(); 48 P tp = *it; 49 int x = tp.second; ll y = a[x]; 50 ll t = a[pre[x]] + a[nxt[x]] - y; 51 a[x] = t; ans += y; 52 st.insert(P(t, x)); 53 st.erase(P(y, x)); 54 if (pre[x]) 55 st.erase(P(a[pre[x]], pre[x])), del(pre[x]); 56 if (nxt[x] && nxt[x] != n + 1) 57 st.erase(P(a[nxt[x]], nxt[x])), del(nxt[x]); 58 } 59 printf("%lld\n", ans); 60 }