首页 > 其他分享 >Minimum Reverse Operations

Minimum Reverse Operations

时间:2023-04-15 15:11:47浏览次数:45  
标签:Operations 状态 Reverse int banned leq Minimum position reverse

Minimum Reverse Operations

You are given an integer n and an integer p in the range [0, n - 1]. Representing a 0-indexed array arr of length n where all positions are set to $0$'s, except position p which is set to 1 .

You are also given an integer array banned containing some positions from the array. For the ith position in banned, `arr[banned[i]] = 0`, and banned[i] != p.

You can perform multiple operations on `arr`. In an operation, you can choose a subarray with size k and reverse the subarray. However, the 1 in arr should never go to any of the positions in banned. In other words, after each operation arr[banned[i]] remains 0 .

Return an array ans where for each i from [0, n - 1], ans[i] is the minimum number of reverse operations needed to bring the 1 to position i in arr, or -1 if it is impossible.

  • A subarray is a contiguous non-empty sequence of elements within an array.
  • The values of ans[i] are independent for all i's.
  • The reverse of an array is an array containing the values in reverse order.

Example 1:

Input: n = 4, p = 0, banned = [1,2], k = 4
Output: [0,-1,-1,1]
Explanation: In this case k = 4 so there is only one possible reverse operation we can perform, which is reversing the whole array. Initially, 1 is placed at position 0 so the amount of operations we need for position 0 is 0. We can never place a 1 on the banned positions, so the answer for positions 1 and 2 is -1. Finally, with one reverse operation we can bring the 1 to index 3, so the answer for position 3 is 1. 

Example 2:

Input: n = 5, p = 0, banned = [2,4], k = 3
Output: [0,-1,-1,-1,-1]
Explanation: In this case the 1 is initially at position 0, so the answer for that position is 0. We can perform reverse operations of size 3. The 1 is currently located at position 0, so we need to reverse the subarray [0, 2] for it to leave that position, but reversing that subarray makes position 2 have a 1, which shouldn't happen. So, we can't move the 1 from position 0, making the result for all the other positions -1. 

 Example 3:

Input: n = 4, p = 2, banned = [0,1,3], k = 1
Output: [-1,-1,0,-1]
Explanation: In this case we can only perform reverse operations of size 1. So the 1 never changes its position.

Constraints:

  • $1 \leq n \leq {10}^5$
  • $0 \leq p \leq n - 1$
  • $0 \leq \text{banned.length} \leq n - 1$
  • $0 \leq \text{banned}[i] \leq n - 1$
  • $1 \leq k \leq n$
  • $\text{banned}[i] \ne p$
  • all values in banned are unique

 

解题思路

  比赛的时候想到用bfs求最短路,结果发现每个状态的转移次数太多了,要bfs的话时间复杂度差不多是$O(nk)$,肯定超时的。

  可以根据$1$所在的不同位置把局面定义为对应的状态(即节点),那么一共有$n$种状态。如果两个状态间能相互转换,那么就在这两个状态之间连一条权值为$1$的边。因此发现可以从状态$p$开始bfs,求到其他状态的最小距离。

  可以发现边的数量非常多,假设当前$1$的所在位置是$x$,要对长度为$k$的区间$[l,r]$进行翻转($l \leq x \leq r$),等价于把$x$变到$r - x + l$。而对于固定长度为$k$的区间翻转,$x$最多变换到$k$个不同的位置,如下图:

  其中区间的左端点$l \in [x - k + 1, x]$,对应的右端点$r \in [x, x + k - 1]$,当然还要保证不能越界。因此可以发现如果在bfs时直接这样枚举每一条边,那么时间复杂度就达到了$O(nk)$了。

  可以发现$x$能变换到的位置的奇偶性都是一样的。假设当前的左端点为$l=i$,那么右端点就是$r=i+k-1$,对区间$[l,r]$翻转那么$x$就会变到$r-x+l = 2i-x+k-1$。当把区间右移一个单位,即$l=i+1$,$r=i+k$,那么$x$就会变到$r-x+l = 2(i+1)-x+k-1$,可以发现变化后的位置的奇偶性都是一样的。

  为此,如果$1$位于$x$处,那么经过一次区间翻转,$x$能够变化到的位置就是$[x-k-1, x-k+1, x-k+3, \ldots, x+k-1]$,当然还要保证不能越界。而事实上根据bfs的性质,如果一个节点已经被更新了,那么到这个节点的最小距离就已经确定了,之后不会再被更新。因此在枚举$x$能够变化到的位置时实际上很多状态都是不会再被更新的了。那么有没有什么做法可以避免枚举到已经不会再更新的状态呢?

  这里提供一个做法,就是开两个平衡树分别存所有奇数的状态和偶数的状态。当要枚举$x$能变化到的状态时,先根据$x-k-1$的奇偶性来判断转移到的状态是奇数还是偶数,然后在对应的平衡树中对区间$[x-k-1, x+k-1]$内还存在的的状态进行更新,并从平衡树中删除。这样就能保证每次枚举到的状态都是还未被更新的状态。查找区间端点以及删除都是$O(\log{n})$的时间复杂度,因此整个bfs的时间复杂度就是$O(n \log{n})$。

  AC代码如下:

 1 class Solution {
 2 public:
 3     vector<int> minReverseOperations(int n, int p, vector<int>& banned, int k) {
 4         vector<bool> vis(n);
 5         for (auto &x : banned) {
 6             vis[x] = true;
 7         }
 8         set<int> st[2];
 9         for (int i = 0; i < n; i++) {
10             if (!vis[i] && i != p) st[i & 1].insert(i);    // 根据奇偶性把数放到对应的平衡树中 
11         }
12         st[0].insert({-0x3f3f3f3f, 0x3f3f3f3f});    // 插入哨兵,保证在二分时有结果 
13         st[1].insert({-0x3f3f3f3f, 0x3f3f3f3f});
14         vector<int> dist(n, -1);
15         dist[p] = 0; 
16         queue<int> q({p});
17         while (!q.empty()) {
18             int t = q.front();
19             q.pop();
20             int x = k - 1 - t & 1;    // 判断x能转移到的状态的奇偶性 
21             auto l = st[x].lower_bound(2 * max(0, t - k + 1) + k - 1 - t);    // 找到最左边能变化到的位置 
22             auto r = st[x].upper_bound(2 * min(n - 1, t + k - 1) - k + 1 - t);    // 找到最右边能变化到的位置 
23             while (l != r) {
24                 dist[*l] = dist[t] + 1;
25                 q.push(*l);
26                 l = st[x].erase(l);    // 从平衡树中删除已被更新的状态 
27             }
28         }
29         return dist;
30     }
31 };

  还可以用并查集来实现上面所说的删除操作。本质上就是找到某个区间内还没有被删除的位置,因此可以开个并查集来维护删除位置的连通性。当要删除一个位置$x$时,那么就将$x$所在的集合的代表元素(其实就是$x$)指向$x+2$所在集合的代表元素(注意要保证奇偶性相同,因此加$2$)。每个集合的代表元素的含义就是当前集合中除了代表元素外,每个元素向右找的第一个还没被删除的位置。

  AC代码如下,时间复杂度为$O(n)$:

 1 class Solution {
 2 public:
 3     vector<int> minReverseOperations(int n, int p, vector<int>& banned, int k) {
 4         vector<int> fa(n + 2);
 5         for (int i = 0; i < n + 2; i++) {
 6             fa[i] = i;
 7         }
 8         function<int(int)> find = [&](int x) {
 9             return fa[x] == x ? fa[x] : fa[x] = find(fa[x]);
10         };
11         for (auto &x : banned) {
12             fa[x] = find(x + 2);
13         }
14         fa[p] = find(p + 2);
15         vector<int> dist(n, -1);
16         dist[p] = 0;
17         queue<int> q({p});
18         while (!q.empty()) {
19             int t = q.front();
20             q.pop();
21             int l = find(2 * max(0, t - k + 1) + k - 1 - t);
22             int r = 2 * min(n - 1, t + k - 1) - k + 1 - t;
23             while (l <= r) {
24                 dist[l] = dist[t] + 1;
25                 q.push(l);
26                 fa[l] = find(l + 2);
27                 l = find(l);
28             }
29         }
30         return dist;
31     }
32 };

 

参考资料

  最少翻转操作数 BFS+平衡树【力扣周赛 339】:https://www.bilibili.com/video/BV1va4y1M7Fr/

标签:Operations,状态,Reverse,int,banned,leq,Minimum,position,reverse
From: https://www.cnblogs.com/onlyblues/p/17320848.html

相关文章

  • Codeforces Round #284 (Div. 1) C. Array and Operations (最大流)
    题目地址:http://codeforces.com/contest/498/problem/C分别分解出每个数字的质因子,然后第奇数个数字的质因子在左边集合,偶数个数字的质因子在右边集合,建立源点和汇点,然后根据每个数字含有的质因子的个数建边,跑一遍最大流即可。代码如下:#include<iostream>#include<string.h>......
  • sort,sorted,reverse,reversed的区别
    python中sort,sorted,reverse,reversed的区别简单的说以上四个内置函数都是排序。对于sort和reverse都是list列表的内置函数,一般不传参数,没有返回值,会改变原列表的值。而sorted和reversed是python内置函数,需要传参数,参数可以是字符串,列表,字典,元组,不管传的参数是什么sorted返回的......
  • How to Configure Nginx reverse proxy the domain
    未测试过,自己记录待用http{resolver8.8.8.8;upstreamexample{serverhttp://example.comresolve[use_last]...;keepalive1024;}第二种负载均衡upstreammytarget{serveraaa.tar.com:443max_fails=3fail_timeout=60s;serverbbb.tar.com:443backup;}server......
  • UCUP-ZJ M. Minimum Element Problem
    题意给定一个位置x,求在\(p_x\)分别取1-n的所有情况下,对应笛卡尔树不同的排列个数。题解先不考虑\(p_x\),列出转移式,发现是卡特兰数。进一步地,可以把排列对应笛卡尔树意义下的不同构数,和二叉树不同构数等价联系起来:因为对于任何一个二叉树,按照中序遍历在上面填1-n,就可以唯一确定......
  • reverse/base64变体类型
    例:【BUU】特殊的BASE64进入main函数后发现rightflag明显是base64加密的结果(补=)随后发现右base64encode函数进入后发现是传统的base64加密方式,猜测是密码表的变体利用shitf+f12查看字符串发现有类似密码表的字符串利用脚本进行解密importbase64outab="ABCDEFGHIJKLMNOP......
  • Linux设备文件三大结构:inode,file,file_operations
    structinodeLinux中一切皆文件,当我们在Linux中创建一个文件时,就会在相应的文件系统创建一个inode与之对应,文件实体和文件的inode是一一对应的,创建好一个inode会存在存储器中,第一次open就会将inode在内存中有一个备份,同一个文件被多次打开并不会产生多个inode,当所有被打开的文件......
  • Maximum and Minimum Height and Width in Internet Explorer
    MaximumandMinimumHeightandWidthinInternetExplorer Beholdtheseventhwonderofthevirtualworld:max/min-heightandmax/min-widthpropertiesarepossi......
  • string_reverse
      defstring_reverse():s="abcdrfg"foriinrange(len(s)-1,-1,-1):print(s[i],end="")gfrdcba  defstring_reverse():......
  • Minimum SDK
    api16android4.1(JellyBean) 100%api17Android4.2(JellyBean) 100%api18Android4.3(JellyBean) 100%api19Android4..4(KitKat)100%api20andr......
  • Codeforces Round 760 (Div. 3) D. Array and Operations(贪心)
    https://codeforces.com/contest/1618/problem/D题目大意:给定一个长度为n的数组a,我们可以进行m次操作:每次操作可以任意选择两个不同的下标的数字x和y,并把它两删除,替换......