CF1350B Orac and Models 题解 DP + 枚举因数

题目链接

这题的本质就是一个最长上升子序列,只不过多加了一个限制

对于求LIS,分别有 O ⁡ ( n 2 ) \operatorname{O}(n^2) O(n2) O ⁡ ( n log ⁡ n ) \operatorname{O}(n \log n) O(nlogn) 两种方法。这题的做法类似第一种

f [ i ] f[i] f[i] 为以 i i i 结尾的最长美丽子序列的长度
对于每个 2 ≤ i ≤ n 2 \le i \le n 2in,考虑从 j j j 转移过来。我们发现它们一定满足 j ∣ i j \mid i ji,那么我们可以用 O ⁡ ( n ) \operatorname{O}(\sqrt n) O(n ) 的枚举因数来枚举 j j j

总时间复杂度 O ⁡ ( n ⋅ n ) \operatorname{O}(n\cdot \sqrt n) O(nn )

#include
#include
#include
using namespace std;
const int Maxn=1000000+10;
int f[Maxn],s[Maxn];
int n,ans;
inline int read()
{
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
	while(ch>='0' && ch<='9')s=(s<<3)+(s<<1)+(ch^48),ch=getchar();
	return s*w;
}
int main()
{
//	freopen("in.txt","r",stdin);
	int T=read();
	while(T--)
	{
		n=read(),ans=1;
		for(int i=1;i<=n;++i)
		s[i]=read(),f[i]=1;
		for(int i=2;i<=n;++i)
		{
			// numerate the divisors of i
			for(int j=1;j*j<=i;++j)
			{
				if(i%j)continue;
				// j is a divisor of i
				if(s[j]<s[i])f[i]=max(f[i],f[j]+1);
				if(j!=i/j && s[i/j]<s[i])f[i]=max(f[i],f[i/j]+1);
			}
			ans=max(ans,f[i]);
		}
		printf("%d\n",ans);		
	}
	return 0;
}

你可能感兴趣的:(题解,#Codeforces)