P4310 绝世好题
基础思路
类似 \(LIS\)。但只有 \(80pts\)
for(int i=1;i<=n;++i)
{
for(int j = 1; j < i; ++j)
{
if(s[i]&s[j])f[i]=max(f[i],f[j]+1);
}
}
优化时间
一种很妙的剪枝。
因为 \(F_i\) 都是由 \(\max(F_j + 1)\) 转移而来,可以用一个数组维护上一轮转移最大的 \(F\) , 这样一旦本轮转移的 \(F[i]\) 已经达到了上一轮最大的 \(F\) 加 \(1\),显然就已经不用继续枚举了,可以 break
。
比较玄学的是,这样剪枝要倒着枚举 \(j\) 才能过,可能涉及按位与的原理,不理解。
#include<cstdio>
#define N 200005
int max(int i,int j){
return i>j?i:j;
}
int n;
int s[N];
int f[N];
int ma[N];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;++i)scanf("%d",&s[i]);
for(int i=1;i<=n;++i)f[i]=1;
for(int i=1;i<=n;++i)
{
for(int j = 1; j < i; ++j)
{
if(f[i] == ma[i-1] + 1)break;
if(s[i]&s[j])f[i]=max(f[i],f[j]+1);
}
ma[i]=max(ma[i-1], f[i]);
}
printf("%d",ma[n]);
return 0;
}
标签:剪枝,绝世,int,max,好题,P4310
From: https://www.cnblogs.com/kdlyh/p/17834203.html