首页 > 其他 > 详细

Codeforces Round #717 (Div. 2) D.Cut 倍增优化

时间:2021-04-22 23:38:46      阅读:19      评论:0      收藏:0      [点我收藏+]

Codeforces Round #717 (Div. 2) D.Cut 倍增优化

题意

给定数组\(a\),每次询问

\[l,r 表示区间[l,r]最少分成多少个子区间,使得子区间的LCM = 子区间的乘积 \]

\[1 \leq n,q \leq 10^5\1 \leq a_i \leq 10^5\1 \leq l,r \leq n \]

分析

容易发现要求就是这个区间任意两个数没有公因子

其实当时贪心已经想到了,但是没想到倍增 这个套路就在前几天的EDU最后一题其实有做到

感觉还是比较常见的套路?类似可见 https://ac.nowcoder.com/acm/contest/82/B

\(go[i][j]\)表示\(i\)出发后\(2^j\)的位置 ,我们发现此题是可以转移的

\[go[i][j] = go[go[i][j-1]][j-1] \]

其中边界即\(go[i][0]\)可以通过预处理每个数后面第一个出现存在过的因子的位置得到

代码

const int maxn = 1e5 + 5;

int isp[maxn],last[maxn],r[maxn],v[maxn],go[maxn][18];
vector<int> g[maxn]; 
int main(){
	 
	for(int i = 2;i <= 100000;i++){
		if(isp[i]) continue;
		for(int j = i;j <= 100000;j += i) {
			g[j].push_back(i);
			isp[j] = 1;
		}
	} 
	int n = rd();
	int q = rd();
	for(int i = 1;i <= n;i++)
		v[i] = rd();
	r[n + 1] = n;
	for(int i = n;i >= 1;i--){
		r[i] = r[i + 1];
		for(auto it:g[v[i]]) {
			if(last[it]) r[i] = min(r[i],last[it] - 1);
		} 
		for(auto it:g[v[i]]) {
			last[it] = i;
		}
	}
	for(int i = 0;i <= 17;i++)
		go[n + 1][i] = n + 1;
	for(int i = n;i >= 1;i--){
		go[i][0] = r[i] + 1;
		for(int j = 1;j <= 17;j++)	
			go[i][j] = go[go[i][j - 1]][j - 1];
	}
	while(q--){
		int l = rd();
		int r = rd();
		int ans = 0 ;
		for(int i = 17;i >= 0;i--){
			if(go[l][i] <= r) 
				ans += (1 << i),l = go[l][i];
		}
		printf("%d\n",ans + 1);
	} 
}

Codeforces Round #717 (Div. 2) D.Cut 倍增优化

原文:https://www.cnblogs.com/hznumqf/p/14691150.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!