前情提要:csdn的app真垃圾啊,既然不能插入代码段,就把代码放正文吧。
A:题目有点搞的,s结尾和l结尾两种情况下x的数量变多判定方式不一样
- void solve() {
- string a, b; cin >> a >> b;
- int n = sz(a), m = sz(b);
- map<char, int> mapp;
- mapp['S'] = 0;
- mapp['M'] = 1;
- mapp['L'] = 2;
- char result;
- if (mapp[a[n - 1]] > mapp[b[m - 1]]){
- result = '>';
- }
- else if (mapp[a[n - 1]] == mapp[b[m - 1]]){
- if (a[n - 1] == 'S')result = n > m ? '<' : n < m ? '>' : '=';
- else if (a[n - 1] == 'L') result = n > m ? '>' : n < m? '<' : '=';
- }
- else result = '<';
- print(result);
- }
- 总结:coding时不够细节,忘记写出所有的情况
B
- void solve() {
- int n; cin >> n;
- vi a(n);
- if (n % 2 == 0){
- for (int i = 0; i < n; ++i) a[i] = i + 1;
- reverse(all(a));
- }
- else{
- for (int i = 0;i < n / 2; ++i){
- a[i] = n - i;
- }
- for (int i = n / 2, t = 0; i < n; ++i){
- a[i] = ++t;
- }
- }
- bl ok = true;
- for (int i = 0; i < n; ++i){
- if (i + 1 == a[i]) {ok = false; break;}
- if (i == 0 && abs(a[i] - a[i + 1]) != 1){
- ok = false; break;
- }
- else if (n == n - 1 && abs(a[i] - a[i - 1]) != 1){
- ok = false; break;
- }
- else if (abs(a[i] - a[i - 1]) != 1 && abs(a[i] - a[i + 1]) != 1){
- ok = false; break;
- }
- }
- if (ok) print(a);
- else print(-1);
- }
- 总结:把奇偶的情况分开,偶数可以直接逆序构造,奇数可以按偶数的方式逆序构造,在构造到中间数时从1开始构造即可
C
- void solve() {
- int n; cin >> n;
- vi a(n); ll l = 0, r = 0;
- map<ll, int> mapp;
- liter(x, a){
- cin >> x; l = max(l, 1ll * x);
- r += x;
- }
- vll prefix(n + 1);
- for (int i = 1; i <= n; ++i){
- prefix[i] += prefix[i - 1] + a[i - 1];
- }
- int result = intmax;
- auto isValid = [&prefix, &result] (ll mid){
- int t = 0;
- ll target = mid;
- int lastindex = 0;
- for (int i = 1; i <= sz(prefix) - 1;){
- int l = i, r = sz(prefix) - 1;
- while (l < r){
- int m = (l + r) >> 1;
- if (prefix[m] - prefix[lastindex] >= target) r = m;
- else l = m + 1;
- }
- if (prefix[l] - prefix[lastindex] != target) {
- return false;}
- i = l + 1;
- t = max(t, l - lastindex);
- lastindex = l;
- }
- result = min(result, t);
- return true;
- };
- vi factors = getFactors(r);
- liter(fac, factors){
- isValid(fac);
- }
- print(result);
- }
- // 根据题意可知每个segment多最小值是数组中最大值,最大值是前缀和。考虑前缀和,如果前缀和可以分成p组,那么p必然是前缀和的一个因子,因为r的范围可以到达2e9,所以从l到r依次求解复杂度过高。需要求出r的所有因子,复杂度为根号(2e9),然后再对每个因子进行分组,再保留最小结果即可。 算法时间复杂度olog(sqrt(r))*(sqrt(r))
- 总结:一眼二分,但是一开始分析错了。题目不应该直接在l和r之间二分。因为如果用每个segment的val值来进行二分,那么判定结果不一定准确。比如实例:4 1 1 1 1 4 (当mid为4时已经成立,就不再判定mid为6),因为mid4的最长长度为4,mid6的最长长度为3.所以并不是segment的值越小长度也越短,所以不能直接在segment的值上二分。明白了这一点后,就知道了只能在区间[l,r]上面跑一遍,然而这样复杂度又太高。所以可以联想到降低复杂度只有在没必要查找的值上下功夫==去除掉lr之间不需要查找的值。而将一个数字分成若干个相等值的区间,这个相等的值一定是这个数字的因子。所以只要求出因子,再bf,就可得到答案。在bf查找能否分成若干个区间时,写了个二分。其实写倍增也可以,或者直接跑数组计算应该也不会TLE。 总的来说,题目没有彻底分析透彻,代码敲的太早了。。
D
- void solve() {
- int n; cin >> n;
- vi a(n + 1);
- ll result = 0;
- for (int i = 1; i <= n; ++i){
- cin >> a[i];
- }
- function<int(int, int)> dfs = [&dfs, &a](int l, int r){
- if (l == r){
- return 0;
- }
- if (l + 1 == r){
- if (a[l] > a[r]) {swap(a[l], a[r]);
- return 1;}
- return 0;
- }
- int cnt = 0, mid = (l + r) >> 1;
- cnt = dfs(l,mid) + dfs(mid + 1, r);
- if (a[l] > a[mid + 1]){
- cnt ++;
- for (int i = l, t = mid + 1; t <= r; ++t, ++i){
- swap(a[i], a[t]);
- }
- }
- return cnt;
- };
- result = dfs(1, n);
- for (int i = 2; i <= n; ++i){
- if (a[i] - 1 != a[i - 1]) {
- print(-1);return;
- }
- }
- print(result);
- }
- 思路:将n个叶子结点递归分成子区间对子区间进行处理。对于一个区间[l, r],如果l ==r,则不需要交换,返回交换次数 = 0;如果左区间左端点大于右区间左端点,说明左右区间需要交换,交换次数为1。从大区间递归的划分为子区间,记录子区间交换次数并在递归调用结束后判定数组是否符合要求即可。
- 总结:一开始以为是类似冒泡排序求交换次数,fenwicktree准备求逆序对后一顿coding后发现理解错题意。题意很明确,就是将pow(2,n)个元素分为了一个又一个的子区间,只需要判断子区间交换后能否满足题意,并且记录交换次数即可。所以逆序对是理解错题意的解法,然后很容易想到利用分治的方法求交换次数了。只要保证子区间有序,并且记录了左右子区间内的交换次数,再判定当前的左右区间是否需要交换即可。 再编程时需要先彻底理解题意,确定思路后再coding。
最后吐槽一下,csdn真垃圾。 请赶紧更新一下ios版的app。