版权声明:转载请注明出处 https://blog.csdn.net/weixin_42557561/article/details/83795029
- 二分(单调性)
- 三分(单峰函数)
- 离散化 (数据范围过大)
- 中位数 O(n)
- 逆序对(归并排序&树状数组)
- 矩阵前缀和
二分
(整数域上的二分)
int l=1,r=1000,ans=0;
while(l<=r){
int mid=l+r>>1;
if(check(mid)) ans=mid,l=mid+1;
else r=mid-1;
}
printf("%d",ans);
(实数域)
double l=1.0,r=1000.0;
while(r-l>=eps){
double mid=(l+r)/2;
if(check(mid)) l=mid;
else r=mid;
}
printf("%lf",l);
三分
double l=1.0,r=1000.0;
while(r-l>=eps){
double ll=l+(r-l)/3.0;
double rr=r-(r-l)/3.0;
if(calc(ll)<calc(rr)) l=ll;
//如果三分得到的左端点比右端点劣,答案一定存在于这个左端点和r之间
else r=rr;
}
printf("%lf",l);
离散化
排序+去重
离散两部曲
sort(b+1,b+n+1);//排序
int m=unique(b+1,b+n+1)-b-1;//去重
for(int i=1;i<=n;++i)
a[i]=lower_bound(b+1,b+m+1,a[i])-b;
中位数
nth_element()差不多是O(n)的效率,比手写快
注意每次搞完的时候只是把需要的放在了你想要的位置上,其他地方还是无序的
double get_middle_num(){
if(n&1){
nth_element(a+1,a+n/2+1,a+n+1);
return a[n/2+1];
}
else{
double x;
nth_element(a+1,a+n/2,a+n+1);x=a[n/2];
nth_element(a+1,a+n/2+1,a+n+1);
x=(x+a[n/2+1])/2;
return x;
}
}
逆序对
树状数组
归并排序
#include<bits/stdc++.h>
#define in read()
#define N 300000
#define ll long long
using namespace std;
inline int read(){
char ch;int f=1,res=0;
while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
while(ch>='0'&&ch<='9') {
res=(res<<3)+(res<<1)+ch-'0';
ch=getchar();
}
return f==1?res:-res;
}
int n,a[N],t[N];
ll ans=0;
inline void mergecount(int l,int mid,int r){
int num=l;//只是改变这个区间,不是1~n好吧!!!!
int i=l,j=mid+1;
while(i<=mid&&j<=r){
if(a[i]>a[j]){
t[num++]=a[j++];
ans+=mid-i+1;
}
else t[num++]=a[i++];
}
while(i<=mid) t[num++]=a[i++];
while(j<=r) t[num++]=a[j++];
for(i=l;i<=r;++i) a[i]=t[i];
}
inline void solve(int l,int r){
if(l==r) return;
int mid=l+r>>1;
solve(l,mid);
solve(mid+1,r);
mergecount(l,mid,r);
}
int main(){
n=in;
int i,j;
for(i=1;i<=n;++i) a[i]=in;
solve(1,n);
cout<<ans;
return 0;
}
矩阵前缀和
for(i=1;i<=n;++i)//插入
for(j=1;j<=m;++j)
sum[i][j]=num[i][j]+sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
ll ans=0;
for(i=r;i<=n;++i)//查询
for(j=c;j<=m;++j)
ans=max(ans,sum[i][j]-sum[i-r][j]-sum[i][j-c]+sum[i-r][j-c]);