求解性→可行性
这个思想非常重要,二分学好了确实可以和很多别的算法巧妙结合。
主要步骤就是二分答案,接着判断能否实现
经典例题:
魔法(二分+dp)
T
e
l
e
p
h
o
n
e
L
i
n
e
s
Telephone Lines
TelephoneLines(二分+最短路)
本题又延伸出来一个新的知识点:判断的时候,可以选取适当的参考,用0,1,-1代替原数(毕竟不考虑求值),这样就可以用最后求出来的结果
O
(
1
)
O(1)
O(1)判断是否合法了
运输计划(运用lca的知识)
二分求lis
该方法简直是神啊,直接把
n
2
n^2
n2变
n
l
o
g
n
nlogn
nlogn
具体做法其实有两种,普通二分,和
l
o
w
e
r
−
b
o
u
n
d
lower-bound
lower−bound函数,但是具体思想是一样的
f
[
i
]
f[i]
f[i]表示,长度为
i
i
i的__子序列的最后一个数字
以上升子序列为例,首先判断当前数字能否构成上升子序列,能的话转移,不能的话,找到第一个大于等于它的数字,代替它
其他的类似
直接给代码吧
int work1()//最长上升子序列
{
memset(f,10,sizeof(f));
pos=1;
f[1]=a[1];
for(int i=2;i<=n;i++)
{
if(a[i]>f[pos]) f[++pos]=a[i];
else
{
int l=1,r=pos;
while(l+1<r)
{
int mid=(l+r)/2;
if(a[i]>f[mid]) l=mid;
else r=mid;
}
if(a[i]<=f[l]) f[l]=a[i];
else f[r]=a[i];
}
}
return pos;
}
int work2()//最长下降子序列
{
memset(f,10,sizeof(f));
pos=1;
f[1]=a[1];
for(int i=2;i<=n;i++)
{
if(a[i]<f[pos]) f[++pos]=a[i];
else
{
int l=1,r=pos;
while(l+1<r)
{
int mid=(l+r)/2;
if(a[i]<f[mid]) l=mid;
else r=mid;
}
if(a[i]>=f[l]) f[l]=a[i];
else f[r]=a[i];
}
}
return pos;
}
int work3()//最长不上升
{
memset(f,10,sizeof(f));
pos=1;
f[1]=a[1];
for(int i=2;i<=n;i++)
{
if(a[i]<=f[pos]) f[++pos]=a[i];
else
{
int l=1,r=pos;
while(l+1<r)
{
int mid=(l+r)/2;
if(a[i]<=f[mid]) l=mid;
else r=mid;
}
if(a[i]>f[l]) f[l]=a[i];
else f[r]=a[i];
}
}
return pos;
}
int work4()//最长不下降
{
memset(f,10,sizeof(f));
pos=1;
f[1]=a[1];
for(int i=2;i<=n;i++)
{
if(a[i]>=f[pos]) f[++pos]=a[i];
else
{
int l=1,r=pos;
while(l+1<r)
{
int mid=(l+r)/2;
if(a[i]>=f[mid]) l=mid;
else r=mid;
}
if(a[i]<f[l]) f[l]=a[i];
else f[r]=a[i];
}
}
return pos;
}
枚举->查找
当写完暴力的时候,不妨关注一下,答案是否具有单调性,如果有,就可能能把枚举,转换成二分查找,把n优化为logn,说不定能多过一些哦!
经典应用:(并非正解)
波波老师(40分)