1 条题解

  • 0
    @ 2025-8-24 21:59:54

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar ytb2024
    我是 闪避 ^_^

    搬运于2025-08-24 21:59:54,当前版本为作者最后更新于2022-12-06 22:12:24,作者可能在搬运后再次修改,您可在原文处查看最新版

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

    以下是正文


    题目传送门

    题意:从头到尾选数,相邻两个数的 gcd\gcd 应大于等于 LL,最多能选多少个数。

    30 pts

    相信很多同学的第一想法是 DP。一维 fif_i 表示选当前的这个数的最大值,可以 O(n2)O\left(n^2\right) 实现。具体为(不会写公式的蒟蒻 qwq),j<ij<igcd(ai,aj)\gcd\left(a_i,a_j\right)\ge LL 时,fi=fj+1f_i=f_j+1fif_i 取最大值。最后 ansans 为所有 fif_i 中的最大值。

    下面是代码实现,就不加注释了。(看一看前面的就知道)

    #include<bits/stdc++.h>
    using namespace std;
    int n,l,a[50001],f[50001],ans=1;
    inline void init()
    {
    	cin>>n>>l;
    	for(int i=1;i<=n;i++)cin>>a[i],f[i]=1;
    }
    inline void solve()
    {
    	for(int i=2;i<=n;i++)
    	{
    		for(int j=1;j<i;j++)if(__gcd(a[i],a[j])>=l)f[i]=max(f[i],f[j]+1);
    		ans=max(ans,f[i]);
    	}
    	cout<<ans;
    }
    int main()
    {
    	ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);
    	init(),solve();
    	return 0;
    }
    

    100 pts

    我们可以发现,题目中的 LLaia_i 不超过 10610^6

    而对 gcd(ai,aj)L\gcd\left(a_i,a_j\right)\ge{L} 的理解可以转化成 aia_iaja_j 的相同约数至少要为 LL

    由于 LLaia_i 很小,所以考虑预处理所有 aia_i 的约数,但是小于 LL 的可以不管(后面会提到)。

    注意:由于此题空间很小,如果数组的第二维开得太大了,就会MLE。这里经过计算后,10610^6 内约数最多(不包含 11)的是 720720720720,有约数 239239 个,所以考虑第二维开 250250

    for(int i=1;i<=n;i++)
    {
    	int x;
    	cin>>x;
    	for(int j=1;j*j<=x;j++)if(x%j==0)
    	{
    		if(j>=l)a[i][++t[i]]=j;
    		if(x/j>=l&&j*j!=x)a[i][++t[i]]=x/j;
    	}
    }
    

    可以发现这相当于一个一个的组,在同一个组的数是可以用前面的更新后面的,而小于 LL 的明显是不可以更新值的,而上面的预处理便是把它的每一个组记录下来。

    可以对每一个组开一个数组,表示这个组中目前的最大值。对于每个数,从它所在的所有组中选最大值,+1+1 后将它在的组全部更新为这个数。

    for(int i=1;i<=n;i++)
    {
    	int sum=0;
    	for(int j=1;j<=t[i];j++)sum=max(sum,maxn[a[i][j]]+1);
    	ans=max(ans,sum);
    	for(int j=1;j<=t[i];j++)maxn[a[i][j]]=sum;
    }
    

    最后输出 ansans 就可以 AC 啦。

    AC代码

    #include<bits/stdc++.h>
    using namespace std;
    int n,l,a[50001][250],t[50001],maxn[1000001],ans;
    inline void init()
    {
    	cin>>n>>l;
    	for(int i=1;i<=n;i++)
    	{
    		int x;
    		cin>>x;
    		for(int j=1;j*j<=x;j++)if(x%j==0)
    		{
    			if(j>=l)a[i][++t[i]]=j;
    			if(x/j>=l&&j*j!=x)a[i][++t[i]]=x/j;
    		}
    	}
    }
    inline void solve()
    {
    	for(int i=1;i<=n;i++)
    	{
    		int sum=0;
    		for(int j=1;j<=t[i];j++)sum=max(sum,maxn[a[i][j]]+1);
    		ans=max(ans,sum);
    		for(int j=1;j<=t[i];j++)maxn[a[i][j]]=sum;
    	}
    	cout<<ans;
    }
    int main()
    {
    	ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);
    	init(),solve();
    	return 0;
    }
    
    • 1

    信息

    ID
    3384
    时间
    1000ms
    内存
    63MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者