【分治思想】

【分治思想】

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;
}
posted @ 2025-07-06 18:02  White_ink  阅读(14)  评论(0)    收藏  举报