这题很神奇。
一开始我读了很久才弄明白红黑树的定义。
然后觉得可能是个构造题,想了一个下午,感觉要很多特判。
又觉得可能是DP,状态是f[i][j]
表示
i
个节点且黑高为
我把转移的表打出来,以为f[i][j]
肯定从二的幂次,或二的幂次减一转移而来,否则记从
x
转移而来,那么似乎
接着就是码码码,一直WA,百度了一下,似乎没结果,只有一篇FJOI2017Day2的游记,好像里面有结论。回头仔细看了看表,发现我的眼睛多半有问题。
看表要仔细啊!
另:这个题目显式地告诉我们红黑树很平衡。
#include<cstdio>
int n,i,j,b[30005][50],k,r[30005][50],bh[30005],f;
inline void up(int&a,int b){
if(a<b)a=b;//,printf("%d %d %d\n",i,j,k);
}
int main(){
for(i=2,bh[1]=1;i<=30000;++i)bh[i]=(1<<bh[i-1])<=i?bh[i-1]+1:bh[i-1];
for(i=3,b[1][1]=r[1][0]=1,b[2][1]=3;i<=30000;++i)
for(j=1;j<=bh[i]<<1;++j)if(j<=30){
if(i==16){
++i;
--i;
}
k=(1<<(j-1))-1;
if(k<i){
if(b[k][j-1] && b[i-k-1][j-1])up(b[i][j],i+b[k][j-1]+b[i-k-1][j-1]);
if(b[k][j-1] && r[i-k-1][j-1])up(b[i][j],i+b[k][j-1]+r[i-k-1][j-1]);
if(r[k][j-1] && b[i-k-1][j-1])up(b[i][j],i+r[k][j-1]+b[i-k-1][j-1]);
if(r[k][j-1] && r[i-k-1][j-1])up(b[i][j],i+r[k][j-1]+r[i-k-1][j-1]);
if(b[k][j] && b[i-k-1][j])up(r[i][j],i+b[k][j]+b[i-k-1][j]);}
k=(1<<j)-1;
if(k<i){
if(b[k][j-1] && b[i-k-1][j-1])up(b[i][j],i+b[k][j-1]+b[i-k-1][j-1]);
if(b[k][j-1] && r[i-k-1][j-1])up(b[i][j],i+b[k][j-1]+r[i-k-1][j-1]);
if(r[k][j-1] && b[i-k-1][j-1])up(b[i][j],i+r[k][j-1]+b[i-k-1][j-1]);
if(r[k][j-1] && r[i-k-1][j-1])up(b[i][j],i+r[k][j-1]+r[i-k-1][j-1]);
if(b[k][j] && b[i-k-1][j])up(r[i][j],i+b[k][j]+b[i-k-1][j]);}
k=i-(1<<(bh[i]-1));
if(k<i){
if(b[k][j-1] && b[i-k-1][j-1])up(b[i][j],i+b[k][j-1]+b[i-k-1][j-1]);
if(b[k][j-1] && r[i-k-1][j-1])up(b[i][j],i+b[k][j-1]+r[i-k-1][j-1]);
if(r[k][j-1] && b[i-k-1][j-1])up(b[i][j],i+r[k][j-1]+b[i-k-1][j-1]);
if(r[k][j-1] && r[i-k-1][j-1])up(b[i][j],i+r[k][j-1]+r[i-k-1][j-1]);
if(b[k][j] && b[i-k-1][j])up(r[i][j],i+b[k][j]+b[i-k-1][j]);}
}
//return 0;
while(scanf("%d",&n)!=EOF && n){
for(f=b[n][i=1];i<=bh[n]<<1;++i)up(f,b[n][i]),up(f,r[n][i]);
printf("%d\n",f);
}
return puts("0"),0;
}