一、二分法
1、基础知识:
1、二分范围
2、二分答案
3、二分时间
2、例题鉴赏:
有一个长度为100000的数组,且a[0]=a[n+1]=-inf,你每次可以查询下表为i的数的值。给你60次查询,求出一个位置使得a[i]>a[i-1]且a[i]>a[i+1],保证所有元素取值不同
做法:每次用三次查询,取mid,mid-1,mid+1,若满足则跳出,否则往大的那一边跳
。。。其它记不到了
二、三分法
其实说白了就是骗分。
三、模拟退火
然而并没有讲
四、博弈论
1、nim游戏
定义:有若干堆石子,每堆石子的数量都是有限的,合法的移动是“选择一堆石子并拿走若干颗(不能不拿)”,如果轮到某个人时所有的石子堆都已经被拿空了,则判负(因为他此刻没有任何合法的移动)。
定义P-position和N-position,其中P代表Previous,N代表Next。直观的说,上一次move的人有必胜策略的局面是P-position,也就是“后手可保证必胜”或者“先手必败”,现在轮到move的人有必胜策略的局面是N-position,也就是“先手可保证必胜”。
计算:一个递归的算法:对于当前的局面,递归计算它的所有子局面的性质,如果存在某个子局面是P-position,那么向这个子局面的移动就是必胜策略。当然,可能你已经敏锐地看出有大量的重叠子问题,所以可以用DP或者记忆化搜索的方法以提高效率。但问题是,利用这个算法,对于某个Nim游戏的局面(a1,a2,…,an)来说,要想判断它的性质以及找出必胜策略,需要计算O(a1*a2*…*an)个局面的性质,不管怎样记忆化都无法降低这个时间复杂度。所以我们需要更高效的判断Nim游戏的局面的性质的方法。
结论
对于一个Nim游戏的局面(a1,a2,…,an),它是P-position当且仅当a1 xor a2 xor … xor an=0。
证明
三个命题:
1、这个判断将所有terminal position判为P-position;
2、根据这个判断被判为N-position的局面一定可以移动到某个P-position;
3、根据这个判断被判为P-position的局面无法移动到某个P-position。
第一个命题显然,terminal position只有一个,就是全0,异或仍然是0。
第二个命题,对于某个局面(a1,a2,…,an),若a1^a2^…^an<>0,一定存在某个合法的移动,将ai改变成ai’后满足a1^a2^…^ai’^…^an=0。不妨设a1^a2^…^an=k,则一定存在某个ai,它的二进制表示在k的最高位上是1(否则k的最高位那个1是怎么得到的)。这时ai^k 小于 ai一定成立。则我们可以将ai改变成ai’=ai^k,此时a1^a2^…^ai’^…^an=a1^a2^…^an^k=0。
第三个命题,对于某个局面(a1,a2,…,an),若a1^a2^…^an=0,一定不存在某个合法的移动,将ai改变成ai’后满足a1^a2^…^ai’^…^an=0。因为异或运算满足消去率,由a1^a2^…^an=a1^a2^…^ai’^…^an可以得到ai=ai’。所以将ai改变成ai’不是一个合法的移动。证毕。
sg函数
例:
int n,sg[maxn];
bool vis[maxn];
void initsg(){
sg[0]=sg[1]=0;
for(int i=2;i<=n;i++){
memset(vis,0,sizeof vis);
for(int j=1;j+j<=i;j++){
vis[sg[i-j]]=1;
}
for(;vis[sg[i]];sg[i]++);
}
}
解题模型:
1.把原游戏分解成多个独立的子游戏,则原游戏的SG函数值是它的所有子游戏的SG函数值的异或。
2.分别考虑没一个子游戏,计算其SG值。
SG值的计算方法
1.可选步数为1~m的连续整数,直接取模即可,SG(x) = x % (m+1);
2.可选步数为任意步,SG(x) = x;
3.可选步数为一系列不连续的数,用模板计算。