小L的序列

小L的数列
比赛主页

我的提交

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 524288K,其他语言1048576K
64bit IO Format: %lld
题目描述
小L喜欢数和数列。小L称a_1…a_na
1

…a
n

这些数为优秀的。小L称一个序列b_1…b_mb
1

…b
m

为好的当且仅当:
1.对于任意的 i (1 \leq i <m)i(1≤i<m),满足 b_i<b_{i+1}b
i

<b
i+1


2.对于任意的 i (1 \leq i <m)i(1≤i<m),满足 gcd(b_i,b_{i+1})>1gcd(b
i

,b
i+1

)>1。其中,gcd(x,y)gcd(x,y) 为 xx 和 yy 的最大公因数,即最大的 dd,满足:d|xd∣x且d|yd∣y。
3.对于任意的 i (1 \leq i \leq m)i(1≤i≤m),b_ib
i

这个数是优秀的。
现在,小L想知道最长的能称为好的的序列的长度是多少,容易证明这个长度是有穷的。

输入描述:
有多组测试点,输入第一行一个数T表示测试点的个数。
对于每一个测试点有两行:
第一行一个正整数 nn,表示优秀的数的个数
第二行 nn 个整数 a_1 … a_na
1

…a
n

,表示小 L 称为优秀的数,保证 a_ia
i

两两不相同。
输出描述:
输出共 TT 行,每一行为一个测试点的答案,即最长的好的序列的长度。
示例1
输入
复制
2
5
4 6 3 2 9
9
10 2 5 3 6 9 7 8 1
输出
复制
4
4
说明
对于第一个测试点来说,一个最长的好的序列可以是 [2, 4, 6, 9],长度为 4 。容易看出没有更长的好的序列。
对于第二个测试点来说,一个最长的好的序列可以是[3, 6, 8, 10],长度为 4 。容易看出没有更长的好的序列。
对于 30%30% 的数据,满足 n, a_i \leq 10n,a
i

≤10。
对于 60%60% 的数据,满足 n, a_i \leq 1000n,a
i

≤1000。
另有 20%20% 的数据,满足n \leq 1000n≤1000。
对于 100%100% 的数据,满足 2 \leq n \leq 100000, 1 \leq a_i \leq 100000, T \leq 5, a_i2≤n≤100000,1≤a
i

≤100000,T≤5,a
i

两两不同。

首先gcd(x,y)>1也就是说他们有相同的大于1的质因子

对于x<y<z,他们都有相同的质因子,那么x和z肯定不相邻。
这句话的意思是当我们拓展这个数的其中一个质因子时,我们只需要枚举到第一个大于它且具有同一个质因子的数即可。

dp[i]表示当前的数为i时的最大合法长度。

#include<iostream>
#include<math.h>
#include<bits/stdc++.h>
using namespace std;
#define maxn 1000000
int dp[maxn];
int a[maxn];
int main()
{

    int t;
    cin>>t;
    while(t--)
    {   memset(dp,0,sizeof dp);
        memset(a,0,sizeof a);
        int n;
        cin>>n;
        for(int i=1;i<=n;i++)
        {
            int x;
            cin>>x;
            a[x]=1;
        }
        int ans=0;
        for(int i=1;i<=100000;i++)
        {
            int t=i;
            if(a[i])//如果当前数存在
            {
                dp[i]=max(dp[i],1);//更新dp【i】
                ans=max(dp[i],ans);//更新答案
            }
            else
                continue;
            for(int j=2;j*j<=100000;j++)//枚举质因数
            {
                if(t%j==0)
                {
                    for(int k=i+j;k<=100000;k+=j)
                    {
                        if(a[k])//如果当前数存在
                        {
                            dp[k]=max(dp[k],dp[i]+1);//看是由i到k大,还是其他方式大。
                            break;
                        }

                    }
                }
                while(t%j==0)
                    t/=j;
            }
            if(t>1)//有一个大于1的根号
            {
                int j=t;
                for(int k=j+i;k<=100000;k+=j)
                {
                    if(a[k])
                    {
                        dp[k]=max(dp[k],dp[i]+1);
                        break;
                    }
                }
            }
        }
        cout<<ans<<endl;
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值