洛谷题单指南-进阶数论-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;
}
浙公网安备 33010602011771号