[9.28模拟] good

题意:给出一个单调递增的序列{\(a_i\)},要你构造一个序列{\(x_i\)},使得:
1、\(x_i\in{\{a_i}\}\)
2、\(\{x_i\}\)单调递增
3、\(gcd(x_i,x_i+1)>1\)
求出最长的\(\{x_i\}\)序列

题解:

dp

dp[i]表示选第i个数的最大长度

显然可以\(n^2\)的实现

考虑如何优化

利用gcd的性质,一个数只会被与它有公共质因子的数转移到,所以当一个数要被与它某一个质因子相同的数转移时,我们只需要考虑已知贡献最大的那个数即可

所以分解出每个数的质因子,利用每一个质因子作为代表进行转移即可

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#define ll long long
#define N 100010
using namespace std;

int n,cnt,ans,dp[N],pri[N],a[N],c[N];
bool mark[N];

vector<int> ve[N];

int gi() {
  int x=0,o=1; char ch=getchar();
  while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar();
  if(ch=='-') o=-1,ch=getchar();
  while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
  return o*x;
}

void pre() {
  for(int i=2; i<=100000; i++) {
    if(!mark[i]) pri[++cnt]=i;
    for(int j=1; j<=cnt && i*pri[j]<=100000; j++) {
      mark[i*pri[j]]=1;
      if(i%pri[j]==0) break;
    }
  }
  for(int j=1; j<=cnt; j++) 
    for(int i=pri[j]; i<=100000; i+=pri[j])
      ve[i].push_back(pri[j]); 
}

int main() {
  n=gi();
  pre();
  for(int i=1; i<=n; i++) a[i]=gi();
  for(int i=1; i<=n; i++) {
    int siz=ve[a[i]].size();
    for(int j=0; j<siz; j++) dp[i]=max(dp[i],c[ve[a[i]][j]]+1);
    for(int j=0; j<siz; j++) c[ve[a[i]][j]]=max(c[ve[a[i]][j]],dp[i]);
  }
  for(int i=1; i<=n; i++) ans=max(ans,dp[i]);
  printf("%d", ans);
  return 0;
}
posted @ 2017-10-01 17:27  HLX_Y  阅读(113)  评论(0编辑  收藏  举报