dp+线性筛——LEETCODE切分数组

线性筛+dp

用埃氏筛好像过不去。。可能是我写的dp太慢了。。

首先可以确定的是这题是可以dp的,对于每个数num[i],将其质因子分解出来,对于每个质因子pi,找到[1..i-1]里所有可以被pi整除的位置pos,用mi[pos-1]去更新mi[i]即可

向右扫描的时候维护一个pos[]数组,pos[i]表示质因子i出现的所有位置x中,mi[x-1]最小的那个

class Solution {
public:
    #define N 1000005
    #define maxn 1000005
    int prime[1000005],m;
    bool vis[maxn];
    void init(){
        for(int i=2;i<maxn;i++){
            if(!vis[i]){
                prime[++m]=i;
            }
            for(int j=1;j<=m;j++){
                if(prime[j]*i>=maxn)break;
                vis[prime[j]*i]=1;
                if(i%prime[j]==0)
                    break;
            }
        }
    }

    int p[N],mm;
    void divide(int x){
        mm=0;
        for(int i=1;i<=m && prime[i]*prime[i]<=x;i++)
            if(x%prime[i]==0){
                p[++mm]=prime[i];
                while(x%prime[i]==0)x/=prime[i];
            }
        if(x>1)p[++mm]=x;
    }

    int mi[N],pos[N];//mi[i]表示i结尾的最小值,pos[i]表示素数i最右的被当成数组结尾的位置
    int splitArray(vector<int>& nums) {
        init();
        int n=nums.size();
        for(int i=0;i<=1e6;i++)mi[i]=pos[i]=1e8;
        divide(nums[0]);
        for(int i=1;i<=mm;i++){
            mi[0]=1;pos[p[i]]=0;
        }

        for(int i=1;i<n;i++){
            divide(nums[i]);
            mi[i]=min(mi[i],mi[i-1]+1);
            for(int j=1;j<=mm;j++){
                if(pos[p[j]]==1e8)continue;
                if(pos[p[j]]==0)mi[i]=1;
                else mi[i]=min(mi[i],mi[pos[p[j]]-1]+1);
            }
            for(int j=1;j<=mm;j++){
                if(pos[p[j]]==0)continue;
                if(pos[p[j]]==1e8)pos[p[j]]=i;
                else if(mi[i-1]<mi[pos[p[j]]-1])
                    pos[p[j]]=i;
            }
        }
        
        return mi[n-1];
    }
};

 

posted on 2020-06-03 19:11  zsben  阅读(182)  评论(0编辑  收藏  举报

导航