• 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
    ",ans);
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    转移虚拟机后ubuntu network available SIOCSIFADDR: No such device
    模板中国剩余定理
    数论 CF27E Number With The Given Amount Of Divisors
    模板 输入输出优化
    模板 欧拉定理
    洛谷P1141 01迷宫
    图论拓扑排序
    归并排序 分治
    HZNUACM寒假集训Day12小结 数论入门 题解
    组合数学基础
  • 原文地址:https://www.cnblogs.com/starve/p/14689402.html
Copyright © 2020-2023  润新知