http://codeforces.com/problemset/problem/632/D
题意:给一段序列和一个正整数m,求这段序列的一个满足条件的最长子序列,条件是这个子序列的最小公倍数小于等于m
第一想法就是暴力,从m枚举到1,对每个当前枚举的值暴力给定序列里有几个是他的因子,然后类似素筛将他的因子全都标记掉,遇到标记的值直接跳过,结果t了,复杂度也不是很好计算,后来想了一些优化也是不可行的,这个方法应该是不可行的
后来想到把这个想法反过来,因为找因子的复杂度会高一写,不如开一个大小为m的数组num【i】,记录每个数 i 在序列里因子的个数,通过序列里的每个数,把他的所有小于m的倍数对应的num值++,最后扫一遍,求出num值最大的那个数即可
复杂度为:m+m/2+m/3+...+m/m (据说叫调和级数)
#include<bits/stdc++.h>
using namespace std;
int book[1000005],book2[1000005];
int a[1000005];
vector <int> ans;
vector <int> num[1000005];
int cmp(int u,int v)
{
return u<v;
}
int main()
{
int n,m,i,j,maxx=0,anss=1;
cin>>n>>m;
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
if(a[i]<=m)
{
num[a[i]].push_back(i);
book2[a[i]]++;
}
}
for(i=1;i<=m;i++)
{
if(book2[i])
for(j=i;j<=m;j+=i)
{
book[j]+=book2[i];
}
}
for(i=1;i<=m;i++)
{
if(book[i]>book[anss])
anss=i;
}
for(i=1;i<=anss;i++)
{
if(anss%i==0)
{
for(j=0;j<num[i].size();j++)
{
ans.push_back(num[i][j]);
}
}
}
sort(ans.begin(),ans.end(),cmp);
cout<<anss<<" "<<book[anss]<<endl;
for(i=0;i<ans.size();i++)
printf("%d ",ans[i]);
cout<<endl;
return 0;
}