【区间倍增dp】D. Cut——Codeforces Round #717 (Div. 2)

D. Cut
time limit per test1 second
memory limit per test256 megabytes
inputstandard input
outputstandard output
This time Baby Ehab will only cut and not stick. He starts with a piece of paper with an array a of length n written on it, and then he does the following:

he picks a range (l,r) and cuts the subsegment al,al+1,…,ar out, removing the rest of the array.
he then cuts this range into multiple subranges.
to add a number theory spice to it, he requires that the elements of every subrange must have their product equal to their least common multiple (LCM).
Formally, he partitions the elements of al,al+1,…,ar into contiguous subarrays such that the product of every subarray is equal to its LCM. Now, for q independent ranges (l,r), tell Baby Ehab the minimum number of subarrays he needs.

Input
The first line contains 2 integers n and q (1≤n,q≤105) — the length of the array a and the number of queries.

The next line contains n integers a1, a2, …, an (1≤ai≤105) — the elements of the array a.

Each of the next q lines contains 2 integers l and r (1≤l≤r≤n) — the endpoints of this query’s interval.

Output
For each query, print its answer on a new line.

Example
inputCopy
6 3
2 3 10 7 5 14
1 6
2 4
3 5
outputCopy
3
1
2
Note
The first query asks about the whole array. You can partition it into [2], [3,10,7], and [5,14]. The first subrange has product and LCM equal to 2. The second has product and LCM equal to 210. And the third has product and LCM equal to 70. Another possible partitioning is [2,3], [10,7], and [5,14].

The second query asks about the range (2,4). Its product is equal to its LCM, so you don’t need to partition it further.

The last query asks about the range (3,5). You can partition it into [10,7] and [5].

思考:
想不出来怎么不超时
而有一个跳跃性的想法
打表空间记录跳多步到哪
用二进制,即这里的g
这叫区间倍增
看懂的开始

dp[i][j]表示从i开始吧序列分为2^j 段最多到哪

专门的介绍
又是Pecco介绍ST表
能找到的CF上最短参考代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
int lst[maxn], a[maxn], f[maxn], g[22][maxn];
int main(){
	int n, q;scanf("%d%d",&n,&q);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int i=1;i<=n;i++) {
		f[i] = f[i-1];
		for(int j=2;j*j<=a[i];++j)
			if(a[i]%j==0){//a[i]不是素数
				f[i]=max(f[i],lst[j]);
				lst[j]=i;
				while(a[i]%j==0)a[i]/=j;
			}
		if(a[i]^1){//a[i]不是1 
			f[i]=max(f[i],lst[a[i]]);
			lst[a[i]]=i;
		}
	}
	for(int i=1;i<=n;++i)g[0][i]=f[i];
	for(int i=1;i<=20;++i)for(int j=1;j<=n;++j)g[i][j]=g[i-1][g[i-1][j]];
	while(q--){
		int l,r,x=0;
		scanf("%d%d",&l,&r);
		for(int i=20;~i;--i)if(g[i][r]>=l)x+=1<<i,r=g[i][r];
		printf("%d\n",x+1);
	}
	return 0;
}

我的

//#pragma GCC optimize(3,"Ofast","inline")
//#pragma GCC optimize(2)
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<time.h>
#include<iostream>
#include<algorithm>
//#include<string>
//#include<sstream>
#include<vector>
#include<map>
//#include<set>
//#include<ctype.h>
//#include<stack>
//#include<queue>
#ifdef LOCAL
FILE*FP=freopen("text.in","r",stdin);
//FILE*fp=freopen("text.out","w",stdout);
#endif
using namespace std;
#define ll long long
#define ld long double
#define pii pair<int,int>
#define piii pair<int,pii>
#define pll pair<ll,ll>
#define plll pair<ll,pll> 
#define pdd pair<double,double>
#define pdi pair<double,int>
#define pid pair<int,double>
#define vi vector <int> 
#define vii vector <vi> 
#define vl vector<ll>
#define st first
#define nd second
#define pb push_back
#define mp make_pair
#define mem(a,b) memset(a,b,sizeof(a))
#define _forplus(i,a,b) for( register int i=(a); i<=(b); i++)
#define forplus(i,a,b) for( register int i=(a); i<(b); i++)
#define _forsub(i,a,b) for( register int i=(a); i>=(b); i--)
#define _forauto(a,b) for(auto &(a):(b))
#define _forautome(a,b,c) for(auto (a) = (b); (a) != (c); (a)++)
#define ALL(x) x.begin(),x.end()
#define INS(x) inserter(x,x.begin())
//参考:set<int>::iterator iter = vis.begin();
#define INF 0x3f3f3f3f
#define LINF 0x3f3f3f3f3f3f3f3f
#define pi (acos(-1))
#define EPS 0.00000001
#define MOD 1000000007
#define fastio 	std::ios::sync_with_stdio(false);std::cin.tie(0);
#define int ll
#define N 100005
int n,q,l,r,sum,a[N],lst[N],g[18][N];//全局数组,未初始化时,默认值都是 0;
//a记录初始数据
//lst记录最后一次i素数出现的序号。我们只要这样看就可以了,即最后一次和这次重复出现的时候就要更新了 
// g[k][i]是从i-(2^k -1)到i区间的最后不符合的序号,有传递性 
int32_t main(){
	fastio
	cin>>n>>q;
	_forplus(i,1,n){
		cin>>a[i];
	}
	_forplus(i,1,n){
		g[0][i]=g[0][i-1];//2^0,就是它本身 
		for(int j=2;j*j<=a[i];j++){
			if(a[i]%j==0){
				g[0][i]=max(g[0][i],lst[j]);//可能有多个因子,取最短的那个 
				lst[j]=i;
			}
			while(a[i]%j==0)a[i]/=j;
		} 
		if(a[i]!=1){//最后是一个质数,这也是因子之一 
			g[0][i]=max(g[0][i],lst[a[i]]);
			lst[a[i]]=i;
		}
	}
	_forplus(i,1,17){
		_forplus(j,1,n){
			g[i][j]=g[i-1][g[i-1][j]];//区间允许度加倍而前移 
		}
	} 
	_forplus(i,1,q){
		cin>>l>>r;
		sum=0; 
		_forsub(i,17,0){
			if(g[i][r]>=l){//因为r是到不了l的,不包含的关系,所以切的是l+0.5,允许出现l 
				sum+=1<<i;
				r=g[i][r];
			}
		}
		cout<<sum+1<<'\n';//落脚点sum个,分为sum+1段 
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值