P5566 [SDOI2008]红黑树 题解
可以通过列出n在较小(如n<14)时的min和max,可以发现min和max的规律
min的规律很好找,可以注意到n=1和n=2时min值即为n=3和n=4时min值,而n=5和n=6时min值则分别为n=1时min值+1和n=2时min值+1。所以将其按2/4/8/……/2^k划分。每一段的前一半就是上一段,后一半则是上一段+1。
但是max的不是很好找,但也可以将max按照2/4/8/16/……/2^k划分的话可以较好发现规律,主要就是每一段前半段为上一段+上一段的第一个数,后半段为前半段+上一段第一个数+1,具体看代码,就不细讲了。
需要注意的是,max的规律有的地方有纰漏,可以观察到从n=2开始,偶数段后半段第一个数比我们的规律推出来少1,奇数段第一个数要多1。所以处理一下。
代码如下(时间复杂度O(N))
#include<bits/stdc++.h>
using namespace std;
int n,minn[5010],maxx[5010],l,r;
int main()
{
cin>>n;
minn[1]=0;minn[2]=1;l=1;r=2;
while(r<n)
{
int len=r-l+1;
for(int i=l+len;i<=r+len;i++)
{
minn[i]=minn[i-len];
}
for(int i=l+len+len;i<=r+len+len;i++)
{
minn[i]=minn[i-len]+1;
}
l=l+len;r=r+len+len;
}
//min的规律
maxx[1]=1;maxx[2]=1;l=1;r=2;int cnt=1;
while(r<n)
{
cnt++;
int len=r-l+1,c=maxx[l];
for(int i=l+len;i<=r+len;i++)
{
maxx[i]=maxx[i-len]+c;
}
for(int i=l+len+len;i<=r+len+len;i++)
{
maxx[i]=maxx[i-len]+c+1;
}
if(cnt%2==0)
{
maxx[l+len+len]-=1;
}
if(cnt%2==1)
{
maxx[l+len]+=1;
}
l=l+len;r=r+len+len;
}//max的规律
cout<<minn[n]<<endl<<maxx[n]<<endl;
return 0;
}