P7810 [JRKSJ R2] Upper

题意

给长为 \(n\) 的序列 \(a\),要求划分为若干段,使得段内左右端点 \(l,r\)\(a[l] < a[r], \gcd(a[l], a[r]) > 1\)\(n \le 10^5, a \le 10^9\)

分析

首先由线性dp。

\(f[i] = \max\limits_{p | a[i]}\max\limits_{j < i, a[j] < a[i],p | a[j]} f[j-1]\)

这样转化为一个二维偏序问题。

然后我们暴力对每个出现过的质因数维护一个动态开点权值线段树。支持前缀 \(\max\) 和单点修改。

空间复杂度 \(\mathcal{O} (n\omega(n)\log n)\),算出来 171 MB。相当稳。

这里有个小技巧,先晒出 \(\sqrt a\) 的素数,每次用素数试除,这样复杂度是 \(\mathcal{O} (\dfrac{\sqrt a}{\log a})\)

还有就是空间复杂度有时按照使用的来算,这样就不要写构造函数了。

#include <bits/stdc++.h>
using namespace std;
#define int long long 
typedef long long ll;
typedef double db;
#define fin(h) freopen(#h".in","r",stdin);
#define fout(h) freopen(#h".out","w",stdout);
inline int read() {
	int x=0,v=1,ch=getchar();
	while('0'>ch||ch>'9') {
		if(ch=='-')v=0;
		ch=getchar();
	}while('0'<=ch&&ch<='9') {
		x=(x*10)+(ch^'0');
		ch=getchar();
	}return v ? x : -x;
}
const int MAX=1e5+5, V = 40000+5, INF = 0x3f3f3f3f;
int n, a[MAX];

vector<int>G[MAX];
int p[V], vis[V];

inline void init(int N = 40000) {
	vis[1] = 1; 
	for(int i=2;i<=N;++i) {
		if(!vis[i]) p[++p[0]] = i;
		for(int j=1;j<=p[0] && i*p[j]<=N;++j) {
			vis[i * p[j]] = p[j];
			if(i % p[j] == 0) break;
		}
	}
}
inline void rho(int j) {
	int x = a[j];
	for(int i=1;p[i]*p[i]<=x;++i) {
		if(x % p[i] == 0) {
			G[j].emplace_back(p[i]);
			while(x % p[i] == 0) x/=p[i];
		}
	} if(x > 1) G[j].emplace_back(x);
}


const int HAHA = MAX;

unordered_map<int,int>HA;

struct seg{
	int rt[MAX];
	struct node {
		int l,r,v;
	}tr[MAX*153];
	int tot;
	inline void ps(int x) { tr[x].v = max(tr[tr[x].l].v, tr[tr[x].r].v); }
	void mdf(int &x,int l,int r, int t, int val) {
		if(!x) x = ++tot;
		if(l==r) {
			tr[x].v = max(tr[x].v, val);
			return ;
		} int mid=l+r>>1;
		if(t<=mid) mdf(tr[x].l,l,mid,t,val);
		else mdf(tr[x].r,mid+1,r,t,val);
		ps(x);
	}
	int ask(int x,int l,int r,int s,int t){
		if(!x) return -INF;
		if(s<=l&&r<=t) return tr[x].v;
		int mid=l+r>>1, ret=-INF; 
		if(s<=mid) ret = max(ret, ask(tr[x].l,l,mid,s,t));
		if(mid<t) ret = max(ret, ask(tr[x].r,mid+1,r,s,t));
		return ret; 
	}
}T;

int f[MAX];
signed main() {
	init();
	n=read();
	for(int i=1;i<=n;++i) {
		a[i] = read();
		rho(i);
	} int cnt = 0;
	f[0] = 0;
	for(int i=1;i<=n;++i) {
		f[i] = -INF;
		for(int v : G[i]) {
			if(!HA.count(v)) HA[v] = ++ cnt, T.rt[cnt] = ++T.tot;
			int t = HA[v];
			f[i] = max(f[i], T.ask(T.rt[t],1, INF, 1, a[i] - 1) + 1);
		}	
		if(f[i-1] >= 0)
			for(int v : G[i]) {
				int t = HA[v];
				T.mdf(T.rt[t], 1, INF , a[i], f[i-1]);
			}
	}
	printf("%lld\n",f[n] < 0? -1 : f[n]);
	return 0;
}
posted @ 2022-09-21 21:41  Lates  阅读(61)  评论(0)    收藏  举报