分治初步
归并排序求逆序对
Sol:在归并排序过程中,本身就是分治思想,递归的对左区间排序,右区间同理。对于已经有序两段进行合并只需要\(O(n)\)的时间,递归共\(log_{2}{n}\)层,时间复杂度为\(O(nlog_{2}{n})\)
debug:1.对于没有到达边界的一段也需要放入临时数组,并且继续统计答案
2,先审核一遍代码,出现了没有调用函数,只打个括号的情况,没有报错,需要注意
int solve(int l,int r){
if(l==r)return 0;
int mid=(l+r)>>1;
int res=solve(l,mid)+solve(mid+1,r);
int pl=l,pr=mid+1;
int cnt=0;
while(pl<=mid&&pr<=r){
if(a[pl]<=a[pr]){
c[++cnt]=a[pl++];
res+=pr-1-(mid+1)+1;
}
else {
c[++cnt]=a[pr++];
}
}
//还需要处理没到边界的一侧
while(pl<=mid){c[++cnt]=a[pl++];res+=pr-(mid+1);}
while(pr<=r)c[++cnt]=a[pr++];
int k=1;
for(int i=l;i<=r;i++)a[i]=c[k++];
return res;
}
void solve(){
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
int ans=solve(1,n);
//for(int i=1;i<=n;i++)cerr<<a[i]<<" ";
cout<<ans<<endl;
}
Codeforces Round 656 (Div. 3) D
a-Good String
定义:字符串s
为一个c-好串
(c 为一个字符)时,必须满足:
-
当\(|s| = 1\) ,\(s = c\)
-
当\(|s| > 1\), \(s\) 的左半部分为全为 \(c\),右半部分为一个
(c+1)-好串
或者 \(s\) 的右半部分为全为 \(c\),左半部分为一个(c+1)-好串
其中 \(|s|\) 代表 字符串 \(s\) 的长度。
举个例子:当 \(s=“cdbbaaaa"\)时,\(s\) 是一个 a-好串
现在,给你一个字符串 \(s\) ( \(|s| = 2^k\) ),问最少替换多少个字符,使其为一个 a-好串
。
Sol:注意题目给出的字符串长度是特殊的,结合题目意思是非常明显的递归求解暗示。每轮中我们只需要决策是选择前半段作为当前轮字母对应段还是后半段。选择以后,另一段的代码递归求解即可,注意递归边界处理。
string s;
int cal(int l,int r,int lev){
int res=0;
char c=lev+'a';
if(l==r){
if(s[l]==c)return 0;
return 1;
}
int mid=(l+r)>>1;
int c1=0,c2=0;
for(int i=l;i<=mid;i++)if(s[i]!=c)c1++;
for(int i=mid+1;i<=r;i++)if(s[i]!=c)c2++;
res=min(c1+cal(mid+1,r,lev+1),c2+cal(l,mid,lev+1));
return res;
}
void solve(){
cin>>n;
cin>>s;
s=" "+s;
int ans=cal(1,n,0);
cout<<ans<<endl;
}
平面最近点对https://www.luogu.com.cn/problem/P1429
P7883 平面最近点对(加强加强版)
给定平面上 \(n\) 个点,找出其中的一对点的距离,使得在这 \(n\) 个点的所有点对中,该距离为所有点对中最小的
数据保证 \(0\le x,y\le 10^9\)
Sol:本题存在\(O(nlogn)\)的解法,对于排序的复杂度采用归并y来降低https://www.luogu.com.cn/article/aihyptbk,这里先给出朴素的\(O(n(log_{}{n})^2)\)做法
整体思路:以x大小为分界线进行分治,左边内部的最近点对递归解决,右边同理。对于左右交界的贡献,首先考虑横坐标距离分界线大于d无法更新答案,对于这些点按y排序,对于其中一个点,纵坐标距离大于d也不可能更新,可以证明一个点可以用来更新答案的点不超过6个(只考虑中坐标比自己大的点,偏序不重复)。
struct node{
db x,y;
bool operator<(const node &A)const{
return x<A.x;
}
}a[N],c[N];
db dis(node c,node d){
db c1=c.x-d.x,c2=c.y-d.y;
return sqrt(c1*c1+c2*c2);
}
db cal(int l,int r){
if(l==r)return 1e12;
int cnt=0;int mid=(l+r)>>1;
db d=min(cal(l,mid),cal(mid+1,r));
for(int i=l;i<=r;i++){
if(fabs(a[i].x-a[mid].x)<d){
c[++cnt].y=a[i].x;
c[cnt].x=a[i].y;
}
}
sort(c+1,c+1+cnt);
for(int i=1;i<=cnt;i++){
for(int j=i+1;j<=cnt&&fabs(c[j].y-c[i].y)<d;j++){
d=min(d,dis(c[i],c[j]));
}
}
return d;
}
void solve(){
//cerr<<18*18*N<<endl;
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i].x>>a[i].y;
sort(a+1,a+1+n);
db ans=cal(1,n);
baoliu(ans,4);
}
标签:递归,好串,int,分治,mid,初步,ans,cal
From: https://www.cnblogs.com/mathiter/p/18199395