【分治思想】
【分治思想】
dfs递归 划分区间
偏暴力写法但降复杂度
Reverse 2^i
https://atcoder.jp/contests/abc413/tasks/abc413_e
写法很像归并排序
merge_sort(q,l,mid); merge_sort(q,mid+1,r);一般都是递归 代码一般都很简洁
题目大意
一个排列,下标从0到1<<n-1,每次可以选择一个二进制区间(0-1,0-3,4-7这种)进行置换,求字典序最小
思路
归并排序方法模拟即可
注意调换时判断区间首位,交换区间即可,不用逆着交换
代码
const int N=(1<<18)+10;
int n;
int p[N];
//从大区间->小区间
//类似归并排序做法
void dfs(int l,int r){
if(l==r) return;
int mid=(l+r)>>1;
dfs(l,mid);dfs(mid+1,r);
if(p[l]>p[mid+1]){//调换区间即可
for(int i=l;i<=mid;i++){
swap(p[i],p[mid+i+1-l]);
}
}
return;
}
void solve(){
int n;
cin>>n;
for(int i=0;i<(1<<n);i++) cin>>p[i];
dfs(0,(1<<n)-1);
for(int i=0;i<(1<<n);i++){
cout<<p[i]<<" ";
}
cout<<endl;
}
浮生众相,独缺其一
https://fjnuacm.top/d/A6666/p/JCPC2025B
题目大意
找到一个最大子串,使得子串内没有任何一个元素等于lcm
思路
lcm:如果要相等只可能是最大数,要么就比最大数大->以最大值为区间分治
如果一个区间不是符合条件的区间,该如何分治?->要忽略最大值的位置再找
代码
int n;
void solve(){
cin>>n;
vector<i64> a(n+1,0);
for(int i=1;i<=n;i++) cin>>a[i];
int ans=0;
auto dfs=[&](auto self,int l,int r){
if(count(a.begin()+l,a.begin()+r+1,a[l])==(r-l+1)){//所有元素都相同
return;
}
if(l>r) return;
i64 k=1LL;
i64 mx=-1;
for(int i=l;i<=r;i++) mx=whink_max<i64>(mx,a[i]);
for(int i=l;i<=r;i++){
k=k*a[i]/gcd(k,a[i]);
if(k>mx){//剪枝:不可能在区间找到lcm
k=-1;
break;
}
}
//按等于拆分区间
if(k!=-1){
int idx=l-1;//拆分点
for(int i=l;i<=r;i++){
if(a[i]==k){
self(self,idx+1,i-1);
idx=i;
}
}
if(idx!=l-1){
self(self,idx+1,r);
}
return;//当前区间不是好区间
}
ans=max(ans,r-l+1);//更新最长区间
};
dfs(dfs,1,n);
cout<<ans<<endl;
}

浙公网安备 33010602011771号