区间倍增dpD. Cut——Codeforces Round #717 (Div. 2)
Posted 出尘呢
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了区间倍增dpD. 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;
}
以上是关于区间倍增dpD. Cut——Codeforces Round #717 (Div. 2)的主要内容,如果未能解决你的问题,请参考以下文章
ST表和倍增算法(Array Stabilization (GCD version)Codeforces Round #717 (Div. 2) D. Cut)
Codeforces Round #717 (Div. 2) D. Cut
Codeforces Round #717 (Div. 2) D. Cut