P11665 题解
TianTian2008 · · 题解
题意
给定序列
引理
Dilworth 定理:对于任意有限偏序集,其最长链中元素的数目必等于其最小反链划分中反链的数目,简称“最长链等于最小反链覆盖”。
那么,
思路
考虑如何求最小反链覆盖,可以贪心地做,维护目前所有已用的不降序列,当新加入元素
因为我们只关心不降序列的结尾,而且不会出现相同结尾,所以可以用
记
但这还不够优,所以我们尝试将可行性 DP 变为数值 DP。
发现我们只关心
每次暴力跳然后更新别的状态即可,时间复杂度不会证,貌似可以势能分析(?),反正我自己没卡掉。
#include <iostream>
#include <cstdio>
using namespace std;
int n,m,k,a[5000001],p[2097152],f[2097152],ans=1000000000;
int main() {
scanf("%d",&n);
for(int i=1;i<=n;++i) {
scanf("%d",&a[i]);
m=max(m,a[i]);
}
k=1<<m;
for(int i=0;i<k;++i) {
p[i]=p[i>>1]+(i&1);
while(f[i]<n-1&&(i>>a[f[i]+1]-1&1|i>>a[f[i]+2]-1&1)) ++f[i];
if(f[i]>=n-1) ans=min(ans,p[i]);
for(int j=0;j<m;++j) {
int x=i|1<<j;
if(x==i) continue;
if(j&&(x>>j-1&1)) x^=1<<j-1;
f[x]=max(f[x],f[i]);
}
}
printf("%d",ans);
return 0;
}