简单
中等
困难
2024-03-06 简单
2917. 找出数组中的 K-or 值
位运算问题,考虑到K-or数只看第i位的值是否为1,并且需要知道的仅仅是超过k值的数组中的数,使用O(n)来解决此问题
简单的位运算模拟。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class Solution {public : int findKOr (vector<int >& nums, int k) { int res = 0 ; for (int i = 0 ; i < 31 ; ++i) { int cnt = 0 ; for (int num:nums) { if ((num >> i) & 1 ){ ++cnt; } } if (cnt >= k) { res |= 1 << i; } } return res; } };
2024-03-07 中等
2575. 找出字符串的可整除数组
考虑到 word 长达 1e5,故无法每一个数字取模确认,因为十进制数字退一位有着 10 个数一循环的特性,故一次取模不影响后面是否会被 m 整除,遂只需要 O(n)即可解决问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class Solution {public : vector<int > divisibilityArray (string word, int m) { int n=word.size (); vector<int > res (n) ; long cur=0 ; for (int i=0 ;i<n;i++){ cur = 10 *cur+((int )word[i]-48 ); cur %= m; if (cur==0 ) res[i]=1 ; else res[i]=0 ; } return res; } };
如何更快?使用位运算可加快计算速度。
2024-03-08 中等
2834. 找出美丽数组的最小和
考虑到一个数可分解为两个数相加,题意为数组中的“两个”数相加不得target,那么如果相等则向下延顺,比如9可分为1 + 8,2 + 7,3 + 6,4 + 5这四组不同的加法,而默认最小数组就是1到n这n个数字,则去除延顺后的最小数组就是[1,2,3,4,9,10,………,n]推出正常情况下的公示,再对1和target不影响默认最小数组的情况特殊判断即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Solution {public : int mod=1e9 + 7 ; long long a_sum (int a,int b,int l) {if (l==1 ) return a; return (long long )(a+b)*l/2 ;} int minimumPossibleSum (int n, int target) { if (n==1 or target==1 ) return a_sum (1 ,n,n)%mod; long long pd= target/2 ; if (pd>n) return a_sum (1 ,n,n)%mod; long long n1=a_sum (1 ,target+n-pd-1 ,target+n-pd-1 ); long long n2=a_sum (pd+1 ,target-1 ,target-pd-1 ); return (n1-n2)%mod; } };
2024-03-09 困难
2386. 找出数组的第 K 大和
一个有n个元素的数组有2^n个子数组,既然是找出第K大的子数组和,那么本题对于给出数组的排序并不敏感,关键是子数组的排序,既然求最大的子数组,那么所有正数相加就是第1个大的子数组,其他子数组就是减去一个最小的正数,或者加上一个最大的负数就是第二个最大子数组….再向后可能就是减去多个正数,加上多个负数….
那么问题转化为只需要求第K个最大子数组的值减去第一个最大子数组的值。使用优先队列的小顶堆维护即可:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Solution {public : long long kSum (vector<int >& nums, int k) { long long s=0 ; int n=nums.size (); for (int &x:nums){ if (x>=0 ) s+=x; else x=-x; } sort (nums.begin (),nums.end ()); priority_queue<pair<long long ,int >,vector<pair<long long ,int >>,greater<>>q; q.push ({0 ,0 }); while (--k) { auto ts=q.top ();q.pop (); if (ts.second>=n) continue ; q.push ({ts.first+nums[ts.second],ts.second+1 }); if (ts.second) q.push ({ts.first-nums[ts.second-1 ]+nums[ts.second],ts.second+1 }); } return s-q.top ().first; } };
2024-03-10 中等
299. 猜数字游戏
使用键值对可以轻松解决此问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class Solution {public : string getHint (string secret, string guess) { unordered_map<char ,int > mp1,mp2; int n=secret.size (); int bulls (0 ) ,cows (0 ) ; for (int i=0 ;i<n;i++){ if (secret[i]==guess[i]){bulls++;continue ;} mp1[secret[i]]++,mp2[guess[i]]++; } for (auto &it:mp1) if (mp2[it.first]) cows+=min (it.second,mp2[it.first]); string ans=to_string (bulls)+"A" +to_string (cows)+"B" ; return ans; } };
2024-03-11 简单
2129. 将标题首字母大写
使用字符流容易解决,还可以避免指针越界。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class Solution {public : string capitalizeTitle (string title) { int n=title.size (); string ans="" ; stringstream ss (title) ; string str; while (ss>>str){ if (str.size ()<=2 ){ ans+=tolower (str[0 ]); if (str.size ()==2 ) ans+=tolower (str[1 ]); }else { int nn=str.size (); ans+=toupper (str[0 ]); for (int i=1 ;i<nn;i++){ ans+=tolower (str[i]); } } ans+=" " ; } ans.pop_back (); return ans; } };
2024-03-12 中等
1261. 在受污染的二叉树中查找元素
二叉树….
2024-03-13 简单
2864. 最大二进制奇数
贪心
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Solution {public : string maximumOddBinaryNumber (string s) { int n=s.size (); int n0 (0 ) ,n1 (0 ) ; for (int i=0 ;i<n;i++) if (s[i]=='0' ) n0++;else n1++; string ans="" ; for (int i=0 ;i<n1-1 ;i++) ans+='1' ; for (int i=n1-1 ;i<n-1 ;i++) ans+='0' ; ans+='1' ; return ans; } };
2024-03-14 中等
2789. 合并后数组中的最大元素
一开始想如果两对两对的看成一个树的结果,维护一个最大的根,后来发现既然只有两个相邻的数,那么直接从后往前加在一块,在不符合规则前取最大的那个不就行了,后来有发现既然他不符合规则,那么后面遍历完的数据就必不可能是答案喽,还是比较容易解决的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class Solution {public : long long maxArrayValue (vector<int >& nums) { int n=nums.size (); long long ans=nums[n-1 ]; for (int i=n-2 ;i>=0 ;i--){ if (nums[i]<=ans){ ans=(long long )ans+(long long )nums[i]; }else { ans=(long long )nums[i]; } } return ans; } };
2024-03-15 困难
2312. 卖木头块
求出卖出方案的最大值,可以确定是DP,题目中说明切割一次只能完全切割,那么如何正确的遍历切割方案和递推公式就是本题的难点。
观察到一个M*N的矩形有2种切割方法,首先是切割成(M1+M2)*N,或者是M*(N1+N2),其中会存在相同的M*N,如果将其记录则优化时间,使用二维数组更新切割的最大值,创建DP。
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 class Solution {public : typedef long long ll; long long sellingWood (int m, int n, vector<vector<int >>& prices) { vector<vector<int >> mp (m+1 ,vector <int > (n+1 ,0 )); for (auto &p:prices) mp[p[0 ]][p[1 ]]=p[2 ]; vector<vector<ll>> dp (m+1 ,vector <ll> (n+1 ,-1 )); function<void (int ,int )> dfs = [&](int i,int j){ if (dp[i][j] != -1 ) return ; dp[i][j]=mp[i][j]; for (int x=i/2 ;x>0 ;x--){ dfs (x,j); dfs (i-x,j); dp[i][j] = max (dp[i][j],dp[x][j]+dp[i-x][j]); } for (int y=j/2 ;y>0 ;y--){ dfs (i,y); dfs (i,j-y); dp[i][j] = max (dp[i][j],dp[i][y]+dp[i][j-y]); } }; dfs (m,n); return dp[m][n]; } };class Solution {public : long long dp[201 ][201 ]; long long sellingWood (int m, int n, vector<vector<int >>& prices) { int i,j,k; for (auto &x : prices) { dp[x[0 ]][x[1 ]] = x[2 ]; } for (int i = 1 ; i <= m; i++) { for (int j = 1 ; j <= n; j++) { for (int k = 1 ; k <= j/2 ; k++) dp[i][j] = max (dp[i][j], dp[i][k] + dp[i][j - k]); for (int k = 1 ; k <= i/2 ; k++) dp[i][j] = max (dp[i][j], dp[k][j] + dp[i - k][j]); } } return dp[m][n]; } };
2024-03-16 2024-03-17 2024-03-18 2024-03-19 2024-03-20 中等
1969. 数组元素的最小非零乘积
基于贪心算法,优先将小的变小,大的变大,最后数组就会成为[0,0,0,0,0,……..,2^p -1,2^p -1,…..],因为要求数组非零,所以再将后面2^p -1的最后一个1补到前面即可,但是不知道为什么,pow(2,p)的效果居然和(ll)1<<(p-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 class Solution {public : typedef long long ll; ll mod=1e9 +7 ; long long my_pow (long long x, long long n) { long long res = 1 ; for (; n != 0 ; n >>= 1 ) { if (n & 1 ) { res = res * x % mod; } x = x * x % mod; } return res; } int minNonZeroProduct (int p) { if (p==1 ) return p; ll a=my_pow ((ll)2 ,p)%mod; ll x=my_pow (2 ,p)-1 ; ll y=(ll)1 <<(p-1 ); return my_pow (x-1 ,y-1 )*x%mod; } };
2024-03-21 中等
2671. 频率跟踪器
第一眼看见直接用map就解决了吗?看到查询次数可能很多,那就动态记录一下num的存量。
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 class FrequencyTracker {public : unordered_map<int ,int > mp; unordered_map<int ,int > cnt; FrequencyTracker () { mp.clear (); cnt.clear (); } void add (int number) { mp[number]++; cnt[mp[number]-1 ]--; cnt[mp[number]]++; } void deleteOne (int number) { if (mp[number]>0 ){ mp[number]--; cnt[mp[number]+1 ]--; cnt[mp[number]]++; } } bool hasFrequency (int frequency) { if (cnt[frequency]>0 ) return true ; return false ; } };
2024-03-22 第 33 次 CCF CSP 认证考试总结 第一题和第二题都很简单,不到 20 分钟就敲完了,全程使用 STL。
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 #include <bits/stdc++.h> using namespace std;#define closeSync \ ios::sync_with_stdio(0); \ cin.tie(0); \ cout.tie(0) map<int , int > mp1; unordered_set<int > st1;int main () { closeSync; int n, m; cin >> n >> m; vector<int > v (m + 1 , 0 ) ; for (int i = 0 ; i < n; i++) { int t; cin >> t; unordered_set<int > st; for (int j = 0 ; j < t; j++) { int word; cin >> word; mp1[word]++; st.insert (word); } for (auto &it : st) { v[it]++; } } for (int i = 1 ; i <= m; i++) { cout << v[i] << " " << mp1[i] << '\n' ; } return 0 ; }
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 #include <bits/stdc++.h> using namespace std;#define closeSync \ ios::sync_with_stdio(0); \ cin.tie(0); \ cout.tie(0) int main () { closeSync; int n, m; cin >> n >> m; unordered_set<string> st1; for (int i = 0 ; i < n; i++) { string s; cin >> s; int sz = s.size (); for (int j = 0 ; j < sz; j++) { if (s[j] >= 'A' and s[j] <= 'Z' ) { s[j] += 32 ; } } st1.insert (s); } unordered_set<string> st2; for (int i = 0 ; i < m; i++) { string s; cin >> s; int sz = s.size (); for (int j = 0 ; j < sz; j++) { if (s[j] >= 'A' and s[j] <= 'Z' ) { s[j] += 32 ; } } st2.insert (s); } unordered_set<string> st3; int n1 = st1.size (); int n2 = st2.size (); set_union (st1.begin (), st1.end (), st2.begin (), st2.end (), inserter (st3, st3.begin ())); int onaji = st3.size (); cout << n1 + n2 - onaji << '\n' ; cout << onaji << '\n' ; return 0 ; }
第三题是对矩阵求秩,有时候想把代码写的好看一点,可是这反而浪费了很多时间,再加上找不到 bug 在哪,让我一度又推翻重写的想法,大概 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 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 #include <bits/stdc++.h> using namespace std;#define closeSync \ ios::sync_with_stdio(0); \ cin.tie(0); \ cout.tie(0) int q, n; vector<vector<int >> a (52 , vector <int >(52 , 0 ));int scan (int ssum) { int r; int cnt = 0 ; for (int i = 1 ; i <= ssum; i++) { for (int j = 1 ; j <= n; j++) { if (a[i][j] != 0 ) { break ; } else cnt++; } if (cnt == n) { return i - 1 ; } cnt = 0 ; } return ssum; }int gcd (int a, int b) { return b == 0 ? a : gcd (b, a % b); }int lcm (int a, int b) { return a / gcd (a, b) * b; }void print (int ssum) { for (int i = 1 ; i <= ssum; i++) { for (int j = 1 ; j <= n; j++) { cout << a[i][j] << " " ; } cout << endl; } cout << endl; }int solve (int ssum) { int l = 1 ; for (int i = 1 ; i <= ssum; i++) { int pd0 = 0 ; for (int j = 1 ; j <= n; j++) { pd0 += a[i][j]; } if (pd0 == 0 ) { l++; continue ; } if (a[i][l] == 0 ) { for (int k = i + 1 ; k <= ssum; k++) { if (a[k][l] != 0 ) { swap (a[i], a[k]); break ; } } } for (int k = i + 1 ; k <= ssum; k++) { int aa = a[i][l], bb = a[k][l]; if (bb == 0 ) continue ; int beishu1 = lcm (aa, bb); int beishu2 = bb * beishu1 / aa; for (int ll = l; ll <= n; ll++) { a[k][ll] *= beishu1; a[k][ll] = a[k][ll] - beishu2 * a[i][ll]; } } if (l < n) l++; else { return l; } } return l; }int main () { closeSync; cin >> q; while (q--) { cin >> n; unordered_map<string, vector<int >> mp; string s; for (int k = 1 ; k <= n; k++) { cin >> s; string elem = "" ; int sz = s.size (); string num_s = "" ; for (int i = 0 ; i < sz; i++) { if (s[i] >= 'a' and s[i] <= 'z' ) elem += s[i]; else { while (s[i] >= '0' and s[i] <= '9' ) num_s += s[i++]; i--; int num = atoi (num_s.c_str ()); if (mp[elem].empty ()) { vector<int > v (52 , 0 ) ; mp[elem] = v; mp[elem][k] += num; } else { mp[elem][k] += num; } elem = "" , num_s = "" ; } } } int Ssum = mp.size (); int ind = 1 ; for (auto &it : mp) { for (int b = 1 ; b <= 50 ; b++) { a[ind][b] = it.second[b]; } ind++; } int R = solve (Ssum); R = scan (Ssum); mp.clear (); cout << ((R < n) ? "Y\n" : "N\n" ); } return 0 ; }
第四题维护一个点以及相邻两个非零点的数值,因为数据非常大(1e9),还需要对数据进行离散化处理,考试的时候是这样想的,大概用了 30 分钟,感觉自己大概率是没发把这个题 100 分过掉,索性在开 3e5 的数组爆搜拿了 40 分。
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 #pragma GCC optimize(2) #pragma GCC optimize(3, "Ofast" , "inline" ) #include <bits/stdc++.h> using namespace std;#define closeSync \ ios::sync_with_stdio(0); \ cin.tie(0); \ cout.tie(0) const int N = 3e5 + 9 ;int a[N];int c, m, n;int search () { int cnt = 0 ; for (int i = 1 ; i <= c; i++) { if (a[i] != 0 ) cnt++; } return cnt; }void opp (int op) { int l = op - 1 , r = op + 1 ; if (l < 0 or r > c + 1 ) return ; if (a[op] >= 5 ) { while (a[l] == 0 and l >= 0 ) { l--; } while (a[r] == 0 and r <= c) { r++; } a[op] = 0 ; a[l]++; a[r]++; } else { return ; } opp (l); opp (r); }int main () { closeSync; cin >> c >> m >> n; int ind = 1 ; for (int i = 1 ; i <= m; i++) { int t1, t2; cin >> t1 >> t2; a[t1] = t2; } while (n--) { int op; cin >> op; a[op]++; opp (op); cout << search () << '\n' ; } return 0 ; }
第五题貌似也是维护一个树形结构?或许也能使用线段树解决,当时只剩下 20 分钟的时间,想使用暴力 STL 嵌套来模拟,最后时间不够了,没用写完。
//代码等待官网上传题目再完善
总结:第一次打 csp,貌似听说同考场有 390 的选手,不由得赞叹校友们的能力,我还缺乏对于模拟过程中的代码的可读性的提高,因为有时候我不知道我在写什么,这也是我第三题浪费了很多时间,再加上机房的电脑没有配置好断点调试,导致我很难找到之前的 bug;另外虽然可带纸质材料,但是基本上是用不上的,翻书更加浪费时间:( 今年还会再打 1~2 次,希望能刷到 400+。