情况 时间:2024年8月4日22:35
题解 A 题意 4n个问题,每个答案正确选项abcd个数都是n。给出答案,有?则无。问你最多对几题。
思路 简单统计。不超过n的都加进去,超过n按n来算。
代码 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 void solve () { int ans[4 ]={0 ,0 ,0 ,0 }; int n; cin >> n; string s; cin >> s; int len = 4 * n; int wen = 0 ; for (int i = 0 ; i < len; i++) { if (s[i] == '?' ) wen++; else ans[s[i] - 'A' ]++; } sort (ans, ans + 4 ); int f = 0 ; for (int i = 0 ; i < 4 ; i++) { if (ans[i] <= n) f += ans[i]; else f += n; } cout << f << endl; }
B 题意 操作:数组中选两个数,奇偶得不同。让两者相加,小的那个换成和。最少几次操作让数组奇偶性一样?
思路 奇数+偶数=奇数。 全是偶数不行,必须得至少一个奇数。 比最大奇数小的偶数一次操作。比最大奇数大的偶数,最多要两次。每次与偶数相加能更新更大的奇数。
代码 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 void solve () { int n; cin >> n; vector<int > a (n) ; int ji = 0 ; vector<int > b (n, 0 ) ; bool flag = false ; for (int i = 0 ; i < n; ++i) { cin >> a[i]; if (a[i] & 1 ) { b[i] = 1 ; flag = true ; ji++; } } if (!flag) { cout << 0 << "\n" ; return ; } else { int maxji = 0 ; int maxou = 0 ; bool flag1 = true ; bool flag2 = true ; sort (a.begin (), a.end ()); for (int i = n - 1 ; i >= 0 ; --i) { if (a[i] % 2 == 1 ) { maxji = a[i]; flag1 = false ; break ; } else { continue ; } } for (int i = 0 ; i < n; ++i) { if (a[i] % 2 == 0 ) { if (maxji > a[i]) { maxji += a[i]; } else { flag2 = false ; break ; } } } if (!flag2) cout << n - ji + 1 << "\n" ; else cout << n - ji << "\n" ; } }
问题 有点冗余,因为刚开始不是最好思路。
C 题意 有一间公寓由 n房间组成,每个房间的灯最初都是关闭 的。 为了控制这些房间的灯光,公寓的主人决定在房间里安装芯片,这样每个房间就只有一个芯片,而且芯片是在不同的时间安装的。具体来说,这些时间由数组 a1,a2,…,an 表示,其中 ai是在 i房间中安装芯片的时间(以分钟为单位)。 一旦安装了芯片,它就每隔 k 分钟改变房间的光状态-它打开光 k 分钟,然后在接下来的 k 分钟关闭它,然后在接下来的 k 分钟重新打开它,等等。换句话说,对于第 i 光状态在分钟 ai 、 ai+k、 ai+2k 、 ai+3k改变。 公寓内所有房间的灯最早在什么时候打开?
思路 只看最大的那个灯的那部分时间段的情况。让前面小的都加到那之前最后“亮”的时间。看:如果最小亮和最大亮的时间差大于等于k,不行。要么,就输出最大亮的时间。
代码 有点冗余,因为刚开始不是最好思路。
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 void solve () { int n, k; cin >> n >> k; vector<int > a (n) ; for (int i = 0 ; i < n; ++i) cin >> a[i]; sort (a.begin (), a.end ()); int max = a[n - 1 ]; for (int i = 0 ; i < n-1 ;i++){ int beishu = max - a[i]; beishu = beishu / k; if (beishu %2 == 1 ) beishu++; a[i] += beishu * k; } sort (a.begin (), a.end ()); int cha = a[n - 1 ] - a[0 ]; if (cha >= k){ cout << "-1" << endl; return ; } else { cout << a[n - 1 ] << endl; } }
D 题意 给数组长度n和每次删的长度k。每次可以删长度为k的一个子区间里的数字。问删到不能删后中位数最大值。
思路 关键点1:找到不排序找中位数的方法。 关键点2:找到最后剩下的数组的规律。 由于每次删长度为连续的k。最终留下来的方案可以理解为:从左到右选择,先选择一个模k为1的位置的数,再选择一个模k为2的未知的数·····
代码 官方 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 #include <bits/stdc++.h> using namespace std;#define int long long #define PII pair<int, int> const int N = 500005 ;int n, k, a[N];int dp[N], b[N];bool check (int med) { for (int i = 0 ; i < n; i++) { if (a[i] >= med) { b[i] = 1 ; } else { b[i] = -1 ; } } dp[0 ] = b[0 ]; for (int i = 1 ; i < n; i++) { if (i % k == 0 ) { dp[i] = max (dp[i - k], b[i]); } else { dp[i] = dp[i - 1 ] + b[i]; if (i > k) { dp[i] = max (dp[i], dp[i - k]); } } } return dp[n - 1 ] > 0 ; } void solve () { cin >> n >> k; for (int i = 0 ; i < n; i++) { cin >> a[i]; } int lo = 1 , hi = 1e9 ; while (lo <= hi) { int mid = lo + hi >> 1 ; if (check (mid)) { lo = mid + 1 ; } else { hi = mid - 1 ; } } cout << hi << '\n' ; } signed main () { ios::sync_with_stdio (false ); cin.tie (0 ); cout.tie (0 ); int T; cin >> T; while (T--) solve (); }
问题 还是有点没懂这dp。而且这题时间复杂度太恶心了。