Codeforces round #717 D.Cut(m询问求区间[L,R]能被至少分成多少个区间让每个小区间各数的乘积==各数的LCM)
题:https://codeforces.com/contest/1516/problem/D
题意:给定n(n<=1e5)个数,q(n<=1e5)个询问,[L,R],问:[L,R]能被至少分成多少个区间让每个小区间各数的乘积==各数的LCM
分析:
- 考虑最简单的求法,对于每个 l ,求出b[l],使得[ l, b[l] ]满足题意,然后迭代l = b[l] 直到 l 超过 r,计数结束;
- 简化这个迭代的过程,考虑dp[ i ][ j ]表示进行了 j = b[ j ] 这个操作 2 ^ i 次到达的位置;
- 而只要算出每个位置迭代1次(即迭代2^0次)就能递推出所有dp[ i ][ j ]( 因为可以满足dp[ i ][ j ] = dp[i - 1][ dp[i - 1][ j ] ] );
- 对于迭代一次的可以预处理每个数的质数,然后从后往前枚举离当前位置pos最近又含与a[pos]不互质的位置 j ,这个位置 j 就是pos迭代一次要跳的位置;
- 因为询问的[L, R]之间的距离肯定可以由一个二进制数来定,所以可以用这个方法。
#include<bits/stdc++.h> using namespace std; #define pb push_back #define MP make_pair #define UM unordered_map #define pii pair<int,int> #define lson root<<1,l,midd #define rson root<<1|1,midd+1,r #define lc root<<1 #define rc root<<1|1 typedef long long ll; const int mod=1e9+7; const int inf=0x3f3f3f3f; const ll INF=1e18; #define pi 3.1415926535898 #define DEC (pi/180) const int M=1e5+5; vector<int>vec[M]; int dp[20][M*10],nextt[M],a[M]; int n,q; void init(){ for(int i=2;i<M;i++){ if(vec[i].size()==0){ nextt[i]=n+1; for(int j=i;j<M;j+=i){ vec[j].pb(i); } } } } int main(){ int T; ///scanf("%d",&T); T=1; while(T--){ scanf("%d%d",&n,&q); for(int i=1;i<=n;i++){ nextt[i]=n+1; scanf("%d",&a[i]); } init(); dp[0][n+1]=n+1; for(int j=n;j>=1;j--){ dp[0][j]=dp[0][j+1]; for(auto v:vec[a[j]]){ dp[0][j]=min(dp[0][j],nextt[v]); nextt[v]=j; } } for(int i=1;i<20;i++) for(int j=1;j<=n+1;j++) dp[i][j]=dp[i-1][dp[i-1][j]]; while(q--){ int L,R; scanf("%d%d",&L,&R); int ans=1; for(int i=19;i>=0;i--){ if(dp[i][L]<=R){ ans+=(1<<i); L=dp[i][L]; } } printf("%d\n",ans); } } return 0; }