cf 264b dp

B. Good Sequences
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Squirrel Liss is interested in sequences. She also has preferences of integers. She thinks n integers a1, a2, ..., an are good.

Now she is interested in good sequences. A sequence x1, x2, ..., xk is called good if it satisfies the following three conditions:

  • The sequence is strictly increasing, i.e. xi < xi + 1 for each i (1 ≤ i ≤ k - 1).
  • No two adjacent elements are coprime, i.e. gcd(xi, xi + 1) > 1 for each i (1 ≤ i ≤ k - 1) (where gcd(p, q) denotes the greatest common divisor of the integers p and q).
  • All elements of the sequence are good integers.

Find the length of the longest good sequence.

Input

The input consists of two lines. The first line contains a single integer n (1 ≤ n ≤ 105) — the number of good integers. The second line contains a single-space separated list of good integers a1, a2, ..., an in strictly increasing order (1 ≤ ai ≤ 105ai < ai + 1).

Output

Print a single integer — the length of the longest good sequence.

Sample test(s)
input
5
2 3 4 6 9
output
4
input
9
1 2 3 5 6 7 8 9 10
output
4
Note

In the first example, the following sequences are examples of good sequences: [2; 4; 6; 9], [2; 4; 6], [3; 9], [6]. The length of the longest good sequence is 4.


 题目要求最长上升子序列,同时必须满足约束条件子序列中相邻两个数必须有公约数。

      假设我们知道了前n-1个数的最长上升子序列,这时加入第n个数a[n],如果想知道以第n个数结尾的最长上升子序列有多长,那么我们就需要找到前n-1个数中与a[n]有公约数的所有a[i],也就是有公因子,并从他们中的取最大值maxLen+1就是以a[n]结尾最长上升长度。因此我们可以将a[n]分解,比如第二个样例中,对于10, 10 = 2*5 ,然后找到前面包含因子2和5数有,2,5,6,8等。。。

关键就在于怎么快速找到前面包含2和5因子结尾的最长长度,因此要存储的状态就变成了fac_dp[i]以质因数i的倍数的结尾的最长子序列多长


#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;

#define maxn 100005

int n;
int a[maxn];
int fac_dp[maxn];   //fac_dp[i]记录包含质因数i的倍数结尾最长子序列多长
int isprime[maxn];  //判断素数
int prime[maxn];    //存储素数因子
int fac[maxn];


int main()
{
    for(int i = 0; i < maxn; i++) isprime[i] = 1;
    isprime[0]=0; isprime[1]=1;

    int cur = 0;
    for(int i = 2; i < maxn; i++)           //预处理找到所有素数因子
        if(isprime[i]){
        prime[cur++] = i;
        for(int j = 2*i; j < maxn; j+=i)
        isprime[j] = 0;
    }



    while(scanf("%d", &n)!=EOF){
        for(int i = 1; i <= n; i++)
            scanf("%d", a+i);

        memset(fac_dp, 0, sizeof(fac_dp)); //初始化为0

        int ans = 0;
        for(int i = 1; i <= n; i++){
            if(isprime[a[i]]){      //如果a[i]为素数,前面必然没有与他有公约数的数,所以长度直接为0
                ans = max(++fac_dp[a[i]], ans);
                continue;
            }

            int cnt = 0;
            int maxi = 0;
            int num = a[i];
            for(int j = 0; j < cur && num>1; j++)  //将a[i]质因数分解
            if(num%prime[j]==0){
                fac[cnt++] = prime[j];
                maxi = max(fac_dp[prime[j]]+1, maxi);
                while(num%prime[j]==0) num/=prime[j];
            }

            ans = max(ans, maxi);
            for(int j = 0; j < cnt; j++)      //更新a[i]所包含的所有素数因子的fac_dp值
                fac_dp[fac[j]] = max(fac_dp[fac[j]], maxi);
        }

        printf("%d\n", ans);
    }
    return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值