基本情况
https://codeforces.com/contest/2207
两道题目,排 2705 还可以,还不赖,感觉。
当然还是有进步的这个空间的。
心得感悟
就是这个 B,哎,感觉基本上是想到了,但是没关注到一个关键的这个数据范围限制 。
一定要关注数据范围限制 。
你看到这个,基本就知道简单的贪心和这个二分答案是解决不了的。
题目 A. 1-1
题目描述
给定一个长度为 n n n 的 01 字符串 s s s 。
在一次操作中,如果存在某个位置 i i i (2 ≤ i ≤ n − 1 2 \le i \le n-1 2 ≤ i ≤ n − 1 )满足其左右相邻的字符均为 1(即 s i − 1 = s i + 1 = 1 s_{i-1} = s_{i+1} = 1 s i − 1 = s i + 1 = 1 ),则可以随意将 s i s_i s i 修改为 0 或 1。
该操作可以执行任意次(包括零次)。你需要求出经过操作后,最终字符串中 1 的数量的最小值和最大值。
输入格式
第一行包含一个整数 t t t (1 ≤ t ≤ 500 1 \le t \le 500 1 ≤ t ≤ 5 0 0 ),表示测试数据的组数。
每组数据包含两行:
第一行为一个整数 n n n (3 ≤ n ≤ 100 3 \le n \le 100 3 ≤ n ≤ 1 0 0 ),表示字符串的长度。
第二行为一个长度为 n n n 的 01 字符串 s s s 。
输出格式
对于每组数据,输出两个整数,分别表示最终字符串中包含 1 的数量的最小值和最大值。
样例输入
1 2 3 4 5 6 7 8 9 4 3 111 6 011011 7 1011101 9 100101101
样例输出
样例解释
在第一组样例中:
在第二组样例中:
https://codeforces.com/contest/2207/problem/A
就是贪心,不难发现,就是能操作的就操作(变为 1),那么得到就是最多的答案 。
接着在能操作的就操作(变为 1),变好的这个串的前提下,然后能操作的就操作(变为 0),得到的就是最少的答案 。
想到这样的方法,一个是 leetcode 好像做过类似思想的题目(和父亲讨论过,没做),还有就是我发现这个进行这个 1 操作后,继续进行 0 操作,得到的答案总归不是不优的,至少是比直接进行 0 操作一样,或者更好。
https://codeforces.com/contest/2207/submission/365935923
源代码
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 #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 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 i128 = __int128;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; cin >> N; string s; cin>>s; s.insert (s.begin (),'#' ); for (int i=2 ;i<=N-1 ;++i) { if (s[i-1 ]=='1' && s[i+1 ]=='1' ) { s[i]='1' ; } } ll mx_ans=count (all (s),'1' ); for (int i=2 ;i<=N-1 ;++i) { if (s[i-1 ]=='1' && s[i+1 ]=='1' ) { s[i]='0' ; } } ll mn_ans=count (all (s),'1' ); cout<<mn_ans<<" " <<mx_ans<<"\n" ; } signed main () { ios::sync_with_stdio (false ); cin.tie (nullptr ); cout.tie (nullptr ); #ifdef LOCAL cout.setf (ios::unitbuf); #endif cin >> lT; for (testcase=1 ;testcase<=lT;++testcase) Solve (); return 0 ; }
题目描述
给定一个高度为 h h h 、列数为 n n n 的网格。在第 i i i 列中,最底部的 a i a_i a i 个格子是泥土,其上方的格子全是水。
你可以在任意一个水格子上放置排水口,最多可以放置两个。
每个排水口可以排走所有能够通过仅向下、向左或向右移动(且不穿过任何泥土格子)到达该排水口的水格子 。被两个排水口共同覆盖的水格子只会被计算一次。
求在最多放置两个排水口 的情况下,能够排走的最大水格子总数 。
输入格式
第一行包含一个整数 t t t (1 ≤ t ≤ 1 0 3 1 \le t \le 10^3 1 ≤ t ≤ 1 0 3 ),表示测试数据组数。
每组数据第一行包含两个整数 n n n 和 h h h (1 ≤ n ≤ 2000 1 \le n \le 2000 1 ≤ n ≤ 2 0 0 0 ,1 ≤ h ≤ 1 0 9 1 \le h \le 10^9 1 ≤ h ≤ 1 0 9 ),分别表示网格的列数和高度。
第二行包含 n n n 个整数 a i a_i a i (1 ≤ a i ≤ h 1 \le a_i \le h 1 ≤ a i ≤ h ),表示第 i i i 列泥土格子的高度。
保证所有测试数据中 n n n 的和不超过 2000 2000 2 0 0 0 。
输出格式
对于每组数据,输出一个单行整数,表示最多能排走的水格子数量。
样例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 Input 6 7 4 1 3 1 2 3 1 1 8 10 7 5 1 3 2 5 6 8 1 1 1 10 20 5 2 1 2 1 3 6 7 1 1 5 1000000000 1 420420420 1 420420420 1 1 1000000000 1 Output 14 43 0 170 3738738738 999999999
样例解释
在第一组样例中,网格列数为 7 7 7 ,高度为 4 4 4 。通过在合适的位置放置两个排水口,最多可以排走 14 14 1 4 个水格子。
在第二组样例中,网格列数为 8 8 8 ,高度为 10 10 1 0 。通过合理放置两个排水口,可以排走网格中全部的 43 43 4 3 个水格子。
在第三组样例中,网格大小为 1 × 1 1 \times 1 1 × 1 ,且唯一的格子是泥土,没有水格子,无法放置排水口,因此输出 0 0 0 。
https://codeforces.com/contest/2207/problem/C
不难发现,这道题目,应该是直接枚举两个的这个抽水的位置,然后 O ( 1 ) O(1) O ( 1 ) 计算其所抽的水。
当然,为了实现这个常数级别的计算,前面需要进行一个 O ( n 2 ) O(n^2) O ( n 2 ) 的预处理。
不难发现,就是抽水棒两边的这个计算(也就是图中绿色部分 的计算)是非常容易的。但是中间蓝色问号部分 的计算,是这道题目的难点。
如果说随意的,错误的进行计算,那么 9 格子就被漏掉了。
通过模拟,我们发现,如果两点之间是一个这个山,那么应该以山峰为界,互不干扰 。
那么山峰是什么东西?就是最大值嘛,这两点之间的最大值的这个坐标就是山峰所在位置 。
1 2 3 4 5 6 7 8 9 10 for (int i=1 ;i<=N;++i) { for (int j=i;j<=N;++j) { ll lans=0 ; ll pos=dp[i][j]; lans=pre_area[i][1 ]+suf_area[i][pos]+pre_area[j][pos]+suf_area[j][N]; lans-=M-H[i]+M-H[pos]+M-H[j]; ans=max (ans,lans); } }
https://codeforces.com/contest/2207/submission/365935937
源代码
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 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 #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 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 i128 = __int128;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,M; cin >> N >> M; vector<ll> H (N+2 ) ; for (int i=1 ;i<=N;++i) { cin>>H[i]; } vector<vector<ll>> suf_area (N+2 ,vector <ll>(N+2 )),pre_area (N+2 ,vector <ll>(N+2 )); for (int i=1 ;i<=N;++i) { ll mx=H[i]; ll res=0 ; for (int j=i;j<=N;++j) { mx=max (H[j],mx); ll add=M-mx; res+=add; suf_area[i][j]=res; } } for (int i=1 ;i<=N;++i) { ll mx=H[i]; ll res=0 ; for (int j=i;j>=1 ;--j) { mx=max (H[j],mx); ll add=M-mx; res+=add; pre_area[i][j]=res; } } ll ans=0 ; vector<vector<ll>> dp (N+2 ,vector <ll>(N+2 )); for (int l=1 ;l<=N;++l) { for (int r=l;r<=N;++r) { if (l==r) { dp[l][r]=l; continue ; } dp[l][r]=dp[l][r-1 ]; if (H[r]>H[dp[l][r-1 ]]) { dp[l][r]=r; } } } for (int i=1 ;i<=N;++i) { for (int j=i;j<=N;++j) { ll lans=0 ; ll pos=dp[i][j]; lans=pre_area[i][1 ]+suf_area[i][pos]+pre_area[j][pos]+suf_area[j][N]; lans-=M-H[i]+M-H[pos]+M-H[j]; ans=max (ans,lans); } } cout<<ans<<"\n" ; } signed main () { ios::sync_with_stdio (false ); cin.tie (nullptr ); cout.tie (nullptr ); #ifdef LOCAL cout.setf (ios::unitbuf); #endif cin >> lT; for (testcase=1 ;testcase<=lT;++testcase) Solve (); return 0 ; }