P4310 绝世好题

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;
}
posted @ 2023-11-15 16:43  加固文明幻景  阅读(23)  评论(0)    收藏  举报