本文最后更新于:星期四, 二月 3日 2022, 9:15 晚上
A. DIY Wooden Ladder
签到。
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 #include <bits/stdc++.h> using namespace std ;#define N 100010 int n;int a[N];int main () { int t; scanf ("%d" , &t); while (t--) { scanf ("%d" , &n); for (int i = 1 ; i <= n; ++i) { scanf ("%d" , a + i); } sort(a + 1 , a + 1 + n); int ans = n - 2 ; ans = min(ans, a[n] - 1 ); ans = min(ans, a[n - 1 ] - 1 ); printf ("%d\n" , ans); } return 0 ; }
B.Pillars
题意:有n n n 根柱子,每根柱子上有一个磁盘,每个磁盘都有自己的半径,第i i i 根柱子上的磁盘能移动到第j j j 根柱子上的前提是:
i i i 和j j j 相邻
第i i i 根柱子上只有一个磁盘
第j j j 根柱子没有磁盘或者顶部磁盘半径大于第i i i 根柱子
问能否将所有磁盘移动到一根柱子上。
思路:很显然只能先递增后递减的形式。
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 #include <bits/stdc++.h> using namespace std ;#define N 200010 int n;int a[N];bool solve () { int Max = 0 , pos = 0 ; for (int i = 1 ; i <= n; ++i) { if (a[i] > Max) { Max = a[i]; pos = i; } } for (int i = 2 ; i <= pos; ++i) { if (a[i] < a[i - 1 ]) { return false ; } } for (int i = pos; i < n; ++i) { if (a[i + 1 ] > a[i]) { return false ; } } return true ; }int main () { while (scanf ("%d" , &n) != EOF) { for (int i = 1 ; i <= n; ++i) { scanf ("%d" , a + i); } puts (solve() ? "YES" : "NO" ); } return 0 ; }
C.Array Splitting
题意:有一个长度为n n n 的序列a a a ,将序列分成k k k 段,使得∑ i = 1 k ( m a x ( i ) − m i n ( i ) ) \sum_{i=1}^{k}(max(i)-min(i)) ∑ i = 1 k ( m a x ( i ) − m i n ( i ) ) 最小,其中m a x ( i ) max(i) m a x ( i ) 表示第i i i 段最大值,m i n ( i ) min(i) m i n ( i ) 表示第i i i 段最小值,且保证a i a_i a i 非降序。
思路:$\sum_{i=1}^k (max(i)-min(i))=a_n-a_1+\sum_{i=1}^{k-1} a_{b_i}-a_{b_i+1} 其 中 其中 其 中 b_i表 示 第 表示第 表 示 第 i段 末 尾 下 标 , 很 显 然 贪 心 选 取 段末尾下标,很显然贪心选取 段 末 尾 下 标 , 很 显 然 贪 心 选 取 k-1$个即可。
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 #include <bits/stdc++.h> using namespace std ;typedef long long ll;#define INF 0x3f3f3f #define N 300010 int n, k; ll a[N];vector <ll> vec;int main () { while (scanf ("%d %d" , &n, &k) != EOF) { vec.clear(); for (int i = 1 ; i <= n; ++i) { scanf ("%lld" , a + i); if (i != 1 ) { vec.push_back(a[i] - a[i - 1 ]); } } sort(vec.begin(), vec.end()); ll ans = a[n] - a[1 ]; for (int len = vec.size(), i = len - 1 ; i >= len - k + 1 ; --i) { ans -= vec[i]; } printf ("%lld\n" , ans); } return 0 ; }
D.Yet Another Subarray Problem
题意:给出一个长度为n n n 的序列a a a ,以及m , k m,k m , k ,求∑ i = l r a i − k ⌈ r − l + 1 m ⌉ \sum_{i=l}^{r}a_i-k\lceil \frac{r-l+1}{m}\rceil ∑ i = l r a i − k ⌈ m r − l + 1 ⌉ 的最大值
思路:d p [ i ] dp[i] d p [ i ] 表示到i i i 节点作为末尾的最大值,对于每个节点i i i 很显然只能选取i i i 前面不到m m m 个数,或者选满m m m 个数后再加上d p [ i − m ] dp[i-m] d p [ i − m ] ,由此转移下去去中间值最大值即可。
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 #include <bits/stdc++.h> using namespace std ;typedef long long ll;#define INF 0x3f3f3f #define N 300010 int n, m, k; ll a[N]; ll dp[N]; ll ans;int main () { while (scanf ("%d %d %d" , &n, &m, &k) != EOF) { for (int i = 1 ; i <= n; ++i) { scanf ("%lld" , a + i); } memset (dp, 0 , sizeof dp); ans = 0 ; for (int i = 1 ; i <= n; ++i) { ll Max = a[i], sum = 0 ; for (int j = i; j >= 1 && j >= i - m + 1 ; --j) { sum += a[j]; Max = max(Max, sum); } dp[i] = max(dp[i], max(Max - k, sum - k + dp[max(i - m, 0 )])); ans = max(ans, dp[i]); } printf ("%lld\n" , ans); } return 0 ; }
E.Culture Code
题意:有n n n 个俄罗斯套娃,每个套娃有两个属性i n , o u t ( o u t > i n ) in,out(out>in) i n , o u t ( o u t > i n ) ,套娃i i i 能放在j j j 对的前提是o u t i < = i n j out_i<=in_j o u t i < = i n j 。
定义一组套娃的额外空间为i n i 1 + ( i n i 2 − o u t i 1 ) + ( i n i 3 − o u t i 2 ) + ⋯ + ( i n i k − o u t i k − 1 ) in_{i_1}+(in_{i_2}-out_{i_1})+(in_{i_3}-out_{i_2})+\cdots+(in_{i_k}-out_{i_{k-1}}) i n i 1 + ( i n i 2 − o u t i 1 ) + ( i n i 3 − o u t i 2 ) + ⋯ + ( i n i k − o u t i k − 1 ) ,其中i 1 , i 2 , ⋯ , i k i_1,i_2,\cdots,i_k i 1 , i 2 , ⋯ , i k 为这组套娃的下标。
定义一组套娃是个极大套娃组:当且仅当不能再有另外一个套娃套在他们身上了。
询问有多少种极大套娃组的额外空间最小
思路:f [ i ] f[i] f [ i ] 表示使用i i i 的最小额外空间,g [ i ] g[i] g [ i ] 为使用i i i 的方案数。对于每个套娃,比它大的最小的俄罗斯套娃。如果和i + 1 i+1 i + 1 套娃的额外空间相同,则加上i + 1 i+1 i + 1 的方案数,如果比i + 1 i+1 i + 1 套娃的额外空间大,则舍弃当前套娃的方案数。
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 #include <bits/stdc++.h> using namespace std ;typedef long long ll;typedef pair <ll, ll> pll;#define INFLL 0x3f3f3f3f3f3f3f #define N 400010 const ll p = (ll) 1e9 + 7 ;int n; pll a[N]; ll f[N], g[N];void add (ll &x, ll y) { x += y; if (x >= p) { x -= p; } }int main () { while (scanf ("%d" , &n) != EOF) { for (int i = 1 ; i <= n; ++i) { scanf ("%lld %lld" , &a[i].second, &a[i].first); } sort(a + 1 , a + 1 + n); f[n + 1 ] = INFLL; for (int i = n; i >= 1 ; --i) { int pos = lower_bound(a + i, a + 1 + n, pll(a[i].second, -1 )) - a; if (pos == n + 1 ) { f[i] = a[i].first; g[i] = 1ll ; } else { f[i] = a[i].first - a[i].second + f[pos]; g[i] = g[pos]; } if (f[i] == f[i + 1 ]) { add(g[i], g[i + 1 ]); } else if (f[i] > f[i + 1 ]) { f[i] = f[i + 1 ]; g[i] = g[i + 1 ]; } } printf ("%lld\n" , g[1 ]); } return 0 ; }