欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 文化 > [算法日常] 根号分治

[算法日常] 根号分治

2025/4/22 4:55:44 来源:https://blog.csdn.net/Brilliant_Sky/article/details/145346085  浏览:    关键词:[算法日常] 根号分治

根号分治

总结:玄学。

难度:玄学。

方法:砍时间复杂度。

根号分治是一种在对数据规模分类讨论的基础上利用不同算法平衡复杂度思想

具体看样例题目。

题目

洛谷 P8572 [JRKSJ R6] Eltaw。

读完题,不难想出前缀和的思想,用 a i , j a_{i,j} ai,j 表示第 i i i 个序列的第 j j j 位前的数字和,俗称前缀和。

分析一下时间复杂度。

如果暴力:

#include<bits/stdc++.h>
using namespace std;
#define ljl long long
const ljl N=5e5+5;
ljl n,k,q,c[750][750];
int main(){ios::sync_with_stdio(0);cin>>n>>k>>q;ljl a[k+1][n+1];memset(a,0,sizeof(a));for(ljl i=1;i<=k;++i){for(ljl j=1;j<=n;++j){ljl t;cin>>t;a[i][j]=a[i][j-1]+t;}}//	if(n<=700)
//	{
//		for(ljl t=1;t<=k;++t)
//			for(ljl i=1;i<=n;++i)
//				for(ljl j=1;j<=n;++j)
//					c[i][j]=max(c[i][j],a[t][j]-a[t][i-1]);
//		while(q--)
//		{
//			ljl l,r;
//			cin>>l>>r;
//			cout<<c[l][r]<<'\n';
//		}
//		return 0;
//	}while(q--){ljl l,r,maxn=0;cin>>l>>r;for(ljl i=1;i<=k;++i)maxn=(ljl)max(maxn,a[i][r]-a[i][l-1]);cout<<maxn<<'\n';}return 0;
}

别看注释,那是正解

这样的时间复杂度是 O ( q k ) O(qk) O(qk) 的,显然会 T 飞。

另一种暴力:

#include<bits/stdc++.h>
using namespace std;
#define ljl long long
const ljl N=5e5+5;
ljl n,k,q,c[750][750];
int main(){ios::sync_with_stdio(0);cin>>n>>k>>q;ljl a[k+1][n+1];memset(a,0,sizeof(a));for(ljl i=1;i<=k;++i){for(ljl j=1;j<=n;++j){ljl t;cin>>t;a[i][j]=a[i][j-1]+t;}}//	if(n<=700)
//	{for(ljl t=1;t<=k;++t)for(ljl i=1;i<=n;++i)for(ljl j=1;j<=n;++j)c[i][j]=max(c[i][j],a[t][j]-a[t][i-1]);while(q--){ljl l,r;cin>>l>>r;cout<<c[l][r]<<'\n';}return 0;
//	}//return 0;
}

这样子的时间复杂度即为 O ( k n 2 ) O(kn^2) O(kn2),等于 O ( 5 ⋅ 1 0 5 n ) O(5\cdot 10^5 n) O(5105n),也会炸飞。

这时候,注意到 n k ≤ 5 × 1 0 5 nk\le 5\times 10^5 nk5×105

那么我们设 s = n k s=nk s=nk

当 $n>\sqrt{s} $ 时, k k k 会比 n n n​ 小,则第一种暴力更优。

时间复杂度进化为 O ( q n k ) O(q\sqrt{nk}) O(qnk )用计算器 算了算,也就大概 3 × 1 0 8 3 \times 10^8 3×108 左右,开个 O2,能过。

k > s k>\sqrt{s} k>s 时, n n n 更小,显然第二种暴力更优。

时间复杂度进化为 O ( s n ) O(sn) O(sn),由于 n n n 比较小,所以也不会炸。

那么就特判一下吧, 5 × 1 0 5 \sqrt{5\times 10^5} 5×105 大概是 700 多,不妨就以 700 为分界点。

AC CODE:

#include<bits/stdc++.h>
using namespace std;
#define ljl long long
const ljl N=5e5+5;
ljl n,k,q,c[750][750];
int main(){ios::sync_with_stdio(0);cin>>n>>k>>q;ljl a[k+1][n+1];memset(a,0,sizeof(a));for(ljl i=1;i<=k;++i){for(ljl j=1;j<=n;++j){ljl t;cin>>t;a[i][j]=a[i][j-1]+t;}}if(n<=700){for(ljl t=1;t<=k;++t)for(ljl i=1;i<=n;++i)for(ljl j=1;j<=n;++j)c[i][j]=max(c[i][j],a[t][j]-a[t][i-1]);while(q--){ljl l,r;cin>>l>>r;cout<<c[l][r]<<'\n';}return 0;}while(q--){ljl l,r,maxn=0;cin>>l>>r;for(ljl i=1;i<=k;++i)maxn=(ljl)max(maxn,a[i][r]-a[i][l-1]);cout<<maxn<<'\n';}return 0;
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词