题目大意
题目大意
有一只魔法山猫会对你进行 n n n 次攻击,每次攻击有一个潜能值 p i p_i p i 。你最终受到的痛苦值为所有未被防御 的攻击潜能值的 mex \text{mex} mex (即未出现在这些潜能值集合中的最小自然数)。
你拥有一个盾牌,激活后可以持续防御接下来的 d d d 次攻击。盾牌失效后会强制进入冷却,冷却时间同样持续 d d d 次攻击,冷却期间无法再次激活。你可以多次激活盾牌,最早可以在第 1 次攻击前激活。
请制定最佳防御策略,使得受到的痛苦值最小。
输入格式
第一行包含两个整数 n n n 和 d d d (1 ≤ n ≤ 1 0 5 1 \le n \le 10^5 1 ≤ n ≤ 1 0 5 , 1 ≤ d ≤ n 1 \le d \le n 1 ≤ d ≤ n ),分别表示攻击总数和盾牌持续/冷却时间。
第二行包含 n n n 个整数 p 1 , … , p n p_1, \dots, p_n p 1 , … , p n (0 ≤ p i < n 0 \le p_i < n 0 ≤ p i < n ),表示每次攻击的潜能值。
输出格式
输出一个整数,表示可以达到的最小痛苦值。
样例 1
解释 :d = 1 d=1 d = 1 。可以在第 1、3、5 次攻击时激活盾牌(防御区间为 [ 1 , 1 ] , [ 3 , 3 ] , [ 5 , 5 ] [1,1], [3,3], [5,5] [ 1 , 1 ] , [ 3 , 3 ] , [ 5 , 5 ] ),冷却区间为 [ 2 , 2 ] , [ 4 , 4 ] [2,2], [4,4] [ 2 , 2 ] , [ 4 , 4 ] 。此时只有潜能为 1 的攻击击中你,mex ( { 1 , 1 } ) = 0 \text{mex}(\{1, 1\}) = 0 mex ( { 1 , 1 } ) = 0 。
样例 2
解释 :d = 2 d=2 d = 2 。无论如何安排,冷却期间总会漏掉潜能为 0 和 1 的攻击。击中你的集合包含 { 0 , 1 } \{0, 1\} { 0 , 1 } ,mex ≥ 2 \text{mex} \ge 2 mex ≥ 2 。
样例 3
1 2 14 2 8 1 1 0 0 2 0 1 2 1 0 6 4 2
可以像图上一样防御。
样例 4
解释 :最早只能在第 1 次攻击前激活,无法同时防御住第 1 个和第 4 个潜能为 0 的攻击(因为防御完第 1 个后,盾牌在第 2、3 个攻击期间防御,第 4 个攻击时可能刚结束或者在冷却,取决于具体激活时机,但无法跨越防御第 1 个和第 4 个而不防御中间的)。选择防御第 2、3 个攻击,漏掉第 1、4 个攻击(潜能均为 0),mex ( { 0 , 0 } ) = 1 \text{mex}(\{0, 0\}) = 1 mex ( { 0 , 0 } ) = 1 。
思路讲解
这道题目其实不是很难,其实就是维护一下可行域就可以了。
那么初始的可行域是从一,就是初始的可行域的左起点是 Max 一和 P 减 d 加一 。右起点就是 P 。然后在后面的过程 当中,我们去不断的更新左起点 。一旦当左起点它比右起点还大的时候 ,左起点比右起点大的时候呢,这个时候就说明我们需要新开一个区间了 。然后我们新开区间的左起点,就是可行域的左端点,就是 L 加2乘以 d 和 P 减 d 加一中取一个 max 如果说然后这个可行域的 R 就是 P 。如果说 L 大于 R 那就说明就进不了可行域。就这个是错的,就 return false 就好了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 auto check=[&](ll val) -> bool { if (g[val].empty ()) { return true ; } ll l=max (1ll ,g[val][0 ]-D+1 ),r=g[val][0 ]; for (int i=1 ;i<g[val].size ();++i) { ll p=g[val][i]; ll to_l=max (l,p-D+1 ); if (to_l>r) { l=max (l+2 *D,p-D+1 ); r=p; if (l>r) { return false ; } }else { l=to_l; } } return true ; };
AC代码
AC
https://qoj.ac/submission/2032675
AC
https://codeforces.com/gym/106129/submission/362772763
源代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 #include <bits/stdc++.h> #define all(vec) vec.begin(),vec.end() #define lson(o) (o<<1) #define rson(o) (o<<1|1) #define SZ(a) ((long long) a.size()) #define debug(var) cerr << #var <<" = [" <<var<<"]" <<"\n" ; #define debug1d(a) \ cerr << #a << " = [" ; \ for (int i = 0; i < (int)(a).size(); i++) \ cerr << (i ? ", " : "" ) << a[i]; \ cerr << "]\n" ; #define debug2d(a) \ cerr << #a << " = [\n" ; \ for (int i = 0; i < (int)(a).size(); i++) \ { \ cerr << " [" ; \ for (int j = 0; j < (int)(a[i]).size(); j++) \ cerr << (j ? ", " : "" ) << a[i][j]; \ cerr << "]\n" ; \ } \ cerr << "]\n" ; #define debug3d(a) \ cerr << #a << " = [\n" ; \ for (int i = 0; i < (int)(a).size(); i++) \ { \ cerr << " [\n" ; \ for (int j = 0; j < (int)(a[i]).size(); j++) \ { \ cerr << " [" ; \ for (int k = 0; k < (int)(a[i][j]).size(); k++) \ cerr << (k ? ", " : "" ) << a[i][j][k]; \ cerr << "]\n" ; \ } \ cerr << " ]\n" ; \ } \ cerr << "]\n" ; #define cend cerr<<"\n-----------\n" #define fsp(x) fixed<<setprecision(x) using namespace std;using ll = long long ;using ull = unsigned long long ;using DB = double ;using CD = complex<double >;static constexpr ll MAXN = (ll)1e6 +10 , INF = (1ll <<61 )-1 ;static constexpr ll mod = 998244353 ; static constexpr double eps = 1e-8 ;const double pi = acos (-1.0 );ll lT,testcase; void Solve () { ll N,D; cin >> N >> D; vector<ll> A (N+2 ) ; vector<vector<ll>> g (N+2 ); set<ll> st_mex; for (int i=0 ;i<N;++i) { st_mex.insert (i); } for (int i=1 ;i<=N;++i) { cin>>A[i]; st_mex.erase (A[i]); g[A[i]].push_back (i); } ll mex=*st_mex.begin (); if (mex==0 ) { cout<<0 <<"\n" ; return ; } auto check=[&](ll val) -> bool { if (g[val].empty ()) { return true ; } ll l=max (1ll ,g[val][0 ]-D+1 ),r=g[val][0 ]; for (int i=1 ;i<g[val].size ();++i) { ll p=g[val][i]; ll to_l=max (l,p-D+1 ); if (to_l>r) { l=max (l+2 *D,p-D+1 ); r=p; if (l>r) { return false ; } }else { l=to_l; } } return true ; }; for (ll i=0 ;i<mex;++i) { if (check (i)) { cout<<i<<"\n" ; return ; } } cout<<mex<<"\n" ; } signed main () { ios::sync_with_stdio (false ); cin.tie (nullptr ); cout.tie (nullptr ); #ifdef LOCAL cout.setf (ios::unitbuf); #endif Solve (); return 0 ; }
心路历程(WA,TLE,MLE……)
这个 check 函数是负责什么呢?是负责检查该 VAL 是否可以被我们的防御魔法所全部覆盖。直接采用这个贪心啊,它其实是没那么简单的。因为虽然说第一个我们肯定是要覆盖的,但是呢我们并不一定要在第一个位置就启用这个防御魔法,我们可以在其更前面的位置启用这个防御魔法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 auto check=[&](ll val) { ll st=-INF; for (auto p:g[val]) { if (p-st+1 <=D) { continue ; } if (p-st+1 <=2 *D) { return false ; } st=p; } return true ; };