1 条题解

  • 0
    @ 2025-8-24 22:33:17

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Spasmodic
    182375

    搬运于2025-08-24 22:33:17,当前版本为作者最后更新于2022-02-19 10:03:47,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    666 AC。

    考虑一个显然的 dp:

    fi=minj<i,aj<ai,(aj,ai)>1fj1f_i=\min\limits_{j<i,a_j<a_i,(a_j,a_i)>1}f_{j-1}

    直接写是 O(n2logv)O(n^2\log v) 的,显然会 t。

    考虑对其进行优化,我们可以枚举 paip|a_i,然后就转化为

    fi=minpaiminj<i,aj<ai,pajfj1f_i=\min_{p|a_i}\min_{j<i,a_j<a_i,p|a_j}f_{j-1}

    考虑后面这个式子,明显可以用权值线段树做,对 aa 离散化的话查询是 O(logn)O(\log n)

    那么我们对于每个质因子,维护一颗权值线段树,并且每次计算完 fi1f_{i-1} 后,枚举 paip|a_ipp 对应的权值线段树上在 aia_i 处更新 fi1f_{i-1}。注意到每次更新的时候其实只有 O(logn)O(\log n) 个结点受到影响,那么采用动态开点线段树就可以把空间控制在 O(nω(v)logn)O(n\omega(v)\log n),其中 ω(n)\omega(n) 表示 nn 的不同质因子数。

    最后对于质因子分解,我们考虑一个简单的优化,在暴力分解的基础上线性筛出质数,然后试除法就可以只用 v\sqrt v 以内的质因子去试,这样复杂度可以少一个 logv\log v

    这样一来时间复杂度就是 O(nπ(v)+nω(v)logn)O(n\pi(\sqrt v)+n\omega(v)\log n),空间是 O(nω(v)logn)O(n\omega(v)\log n),轻松通过。

    // Problem: P7810 [JRKSJ R2] Upper
    // Contest: Luogu
    // URL: https://www.luogu.com.cn/problem/P7810?contestId=48251
    // Memory Limit: 256 MB
    // Time Limit: 1500 ms
    // 
    // Powered by CP Editor (https://cpeditor.org)
    
    #include<bits/stdc++.h>
    #define endl '\n' 
    #define rep(i,a,b) for(int i=(a);i<=(b);++i)
    #define Rep(i,a,b) for(int i=(a);i>=(b);--i)
    using namespace std;
    const int P=998244353;
    void chkmax(int &x,int y){if(x<y)x=y;}
    void chkmin(int &x,int y){if(x>y)x=y;}
    int qpow(int a,int k){
    	int ret=1;
    	while(k){
    		if(k&1)ret=ret*(long long)a%P;
    		a=a*(long long)a%P;
    		k>>=1;
    	}
    	return ret;
    }
    int qpow(int a,int k,int p){
    	int ret=1;
    	while(k){
    		if(k&1)ret=ret*(long long)a%p;
    		a=a*(long long)a%p;
    		k>>=1;
    	}
    	return ret;
    }
    int norm(int x){return x>=P?x-P:x;}
    int reduce(int x){return x<0?x+P:x;}
    void add(int&x,int y){if((x+=y)>=P)x-=P;}
    struct IO_Tp {
        const static int _I_Buffer_Size = 2 << 22;
        char _I_Buffer[_I_Buffer_Size], *_I_pos = _I_Buffer, *_I_end= _I_Buffer + _I_Buffer_Size;
    
        const static int _O_Buffer_Size = 2 << 22;
        char _O_Buffer[_O_Buffer_Size], *_O_pos = _O_Buffer;
    
        IO_Tp() { fread(_I_Buffer, 1, _I_Buffer_Size, stdin); }
        ~IO_Tp() { fwrite(_O_Buffer, 1, _O_pos - _O_Buffer, stdout); }
    
        IO_Tp &operator>>(int &res) {
        	int f=1;
            while (_I_pos!=_I_end&&!isdigit(*_I_pos)&&(*_I_pos)!='-') ++_I_pos;
            assert(_I_pos!=_I_end);
            if(*_I_pos=='-')f=-1,++_I_pos;
            res = *_I_pos++ - '0';
            while (_I_pos!=_I_end&&isdigit(*_I_pos)) res = res * 10 + (*_I_pos++ - '0');
            res*=f;
            assert(_I_pos!=_I_end);
            return *this;
        }
        
        IO_Tp &operator>>(string &res){
        	res="";
        	auto blank=[&](char ch){
        		if(ch==' '||ch=='\n'||ch=='\r'||ch=='	'||ch=='\0')return 1;
        		return 0;
    		};
    		while(_I_pos!=_I_end&&blank(*_I_pos)) ++_I_pos;
        	while (_I_pos!=_I_end&&!blank(*_I_pos))res += *_I_pos++;
        	assert(_I_pos!=_I_end);
        	return *this;
    	} 
    
        IO_Tp &operator<<(int n) {
        	if(n<0)*_O_pos++='-',n=-n;
            static char _buf[10];
            char *_pos = _buf;
            do
                *_pos++ = '0' + n % 10;
            while (n /= 10);
            while (_pos != _buf) *_O_pos++ = *--_pos;
            return *this;
        }
    
        IO_Tp &operator<<(char ch) {
            *_O_pos++ = ch;
            return *this;
        }
        
        IO_Tp &operator<<(string &res){
        	for (char ch:res) *_O_pos++ = ch;
        	return *this;
    	} 
    } IO;
    const int N=1e5+5;
    int n,m,a[N],sa[N],ua[N],f[N],cnt[N],pr[N][10];
    int cp,p[N];
    bool vst[N];
    void init(int n){
    	rep(i,2,n){
    		if(!vst[i])p[++cp]=i;
    		for(int j=1;j<=cp&&i*p[j]<=n;j++){
    			vst[i*p[j]]=1;
    			if(i%p[j]==0)break;
    		}
    	}
    }
    void dcp(int id){
    	int x=a[id];
    	for(int i=1;p[i]*p[i]<=x;i++)if(x%p[i]==0){
    		pr[id][++cnt[id]]=p[i];
    		while(x%p[i]==0)x/=p[i];
    	}
    	if(x>1)pr[id][++cnt[id]]=x;
    }
    unordered_map<int,int>rt;
    int tot;
    struct node{
    	int lc,rc,ma;
    }st[N<<5];
    void pushup(int k){st[k].ma=max(st[st[k].lc].ma,st[st[k].rc].ma);}
    void insert(int&k,int l,int r,int p,int v){
    	if(!k)k=++tot;
    	if(l==r)return chkmax(st[k].ma,v),void();
    	int mid=l+r>>1;
    	if(p<=mid)insert(st[k].lc,l,mid,p,v);
    	else insert(st[k].rc,mid+1,r,p,v);
    	pushup(k);
    	return;
    }
    int ask(int p,int l,int r,int x,int y){
    	if(!p)return -2;
    	if(x<=l&&r<=y)return st[p].ma;
    	int mid=l+r>>1,ret=-2;
    	if(x<=mid)chkmax(ret,ask(st[p].lc,l,mid,x,y));
    	if(mid<y)chkmax(ret,ask(st[p].rc,mid+1,r,x,y));
    	return ret;
    }
    int main(){
    	IO>>n;
    	init(1e5);
    	rep(i,1,n)IO>>a[i],sa[i]=a[i],dcp(i);
    	sort(sa+1,sa+n+1);
    	m=unique(sa+1,sa+n+1)-sa-1;
    	rep(i,1,n)ua[i]=lower_bound(sa+1,sa+m+1,a[i])-sa;
    	memset(f,-1,sizeof f);
    	f[0]=0;
    	rep(i,1,n){
    		rep(j,1,cnt[i]){
    			int p=rt[pr[i][j]];
    			chkmax(f[i],ask(p,1,m,1,ua[i]-1)+1);
    			if(f[i-1]>=0)insert(p,1,m,ua[i],f[i-1]);
    			rt[pr[i][j]]=p;
    		}
    	}
    	IO<<f[n]<<endl;
    	return 0;
    }
    
    • 1

    信息

    ID
    7117
    时间
    1500ms
    内存
    256MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者