https://www.cnblogs.com/DaD3zZ-Beyonder/archive/2015/10.html
加油啊布丁酱!
跳过了一个LIS的随笔。(LIS类似升序的单调队列,有模板的题先不看了)
2704:寻找平面上的极大点
先按x的大于序排序,再按y的大于序排序。从第一个点开始找,记录当前最大的y,每次新的y比当前y大的时候更新y。 $O(nlogn)$
2469:电池的寿命
首先看到这里的直觉就是总电量的一半(因为是连续的,所以可以通过几颗电池去削减大电池的电量,构成两个相等的电池之后可以轮流削减两个相等的电池的电量指直到自己的电量耗完,再把两颗剩余的相等的电池耗完,这样就证明每三颗(比较平均的)电池都可以完全利用,类似的思路可以猜测都是可以完全削减的),但是我少考虑了一种情况,就是有一颗超大的电池,要把其他的电池都和他匹配。
1768:最大子矩阵
这么小的数据量可以用前缀和,暴力枚举每个子矩阵查询 $O(n^4)$ 。学长也是用暴力枚举的,不知道他怎么卡过去的。搜了一下解法,可以压缩一个维度,比如先用前缀和支持了 $O(1)$ 查询,然后 $dp[i][j][k]$ 表示以 $(i,j)$ 为右下角,高度为 $k$ 的最大子矩阵,那么每次从左到右转移的时候, $dp[i][j][k]=dp[i][j-1][k]>=0?(dp[i][j-1][k]+sum(i,j,k)):sum(i,j,k))$ ,也就是最长上升子串的dp方法,这样是 $O(n^3)$ 。
7617:输出前k大的数
数据量太小了导致可以直接sort,而先用nth_element()之后还是要sort(因为数据量太大不能桶排序)。
7622:求排列的逆序数
可以使用归并排序的修改来统计逆序数,也就是先分治,然后右边的每次出队的时候,这个元素对应的逆序数就是左边队列中剩余的元素的数量,之前的那道题突然就会解决了!布丁酱加油!
#include<iostream> #include<cstdio> using namespace std; int a[100010]= {0},L[100010]= {0},R[100010]= {0}; long long ans=0; #define M 1000000000; void gb(int left,int mid,int right) { int ll=mid-left+1; int lr=right-mid; for (int i=1; i<=ll; i++) L[i]=a[left+i-1];//此操作方便处理 for (int i=1; i<=lr; i++) R[i]=a[mid+i]; L[ll+1]=M;//将最后一个赋给一个极大值,可以当作一个“哨兵”非常的精妙,然而经测试似乎不加这条语句会出错 R[lr+1]=M; int l=1,r=1; for (int i=left; i<=right; i++) { if (L[l]<=R[r]) { a[i]=L[l]; l++; } else { a[i]=R[r]; r++; ans+=ll-l+1;//求逆序对的唯一多出来的语句 } } } void gbsort(int left,int right) { int mid=(left+right)/2; if (left<right) { gbsort(left,mid);//不断分治 gbsort(mid+1,right); gb(left,mid,right); } } int main() { int n; scanf("%d",&n); for (int i=1; i<=n; i++) scanf("%d",&a[i]); gbsort(1,n); printf("%lld",ans); return 0; }