洛谷题单指南-进阶数论-CF632D Longest Subsequence

原题链接:https://www.luogu.com.cn/problem/CF632D

题意解读:找个最长子序列,使得其LCM<=m

解题思路:

LCM最大值为1000000,不妨枚举这个LCM,然后看有多个数是其约数,这样做时间复杂度为n*m。

换一个角度,从每个数出发,通过类似埃氏筛的方式将其倍数(<=m)进行标记+1,最终看被标记次数最多的数即可。

直接从每个数出发,复杂度可能过高,先最数据进行排序,只取<=m的部分,再去重,这样对于一个数的倍数的标记应该加上这个数的个数,

如此优化,整体复杂度可以做到n*logm

100分代码:

#include <bits/stdc++.h>
using namespace std;

const int N = 1000005;

int a[N], b[N], h[N], ans[N];
int n, m;

int main()
{
    cin >> n >> m;
    for(int i = 1; i <= n; i++) cin >> a[i];
    for(int i = 1; i <= n; i++) 
    {
        b[i] = a[i]; //b是a的拷贝
        if(b[i] <= m) h[b[i]]++; //h记录b中每个数出现的次数
    }
    sort(b + 1, b + n + 1);
    int bn = unique(b + 1, b + n + 1) - (b + 1); //对b排序,去重
    for(int i = 1; i <= bn; i++)
    {
        for(int j = b[i]; j <= m; j += b[i])
        {
            ans[j] += h[b[i]];
        }
    }
    int lcm = 1, cnt = 0;
    for(int i = 1; i <= m; i++) 
    {
        if(ans[i] > cnt)
        {
            cnt = ans[i];
            lcm = i;
        }
    }
    cout << lcm << " " << cnt << endl;
    if(cnt > 0)
    {
        for(int i = 1; i <= n; i++)
        {
            if(lcm % a[i] == 0) cout << i << " ";
        }
    }
    return 0;
}

 

posted @ 2025-10-21 16:10  hackerchef  阅读(6)  评论(0)    收藏  举报