今天是ACM校内赛。虽然我没学过OI,没有退役的感觉,但很有可能之后就不打ACM了。
这里很感谢队友的帮助,过了2道题,有希望拿奖。
自己做的是F题,求
(7+43√)n
的整数部分。
一下子想到初中数学竞赛,
an=(7+43√)n+(7−43√)n
是整数。
怎么证的?求出递推方程
an+1=4an−an−1
. 归纳法
那么怎么求呢?说来真是一段历史。
初中时我会递推地求,至少比硬算快,高中时我会求出用特征方程通项公式,厉害吧,现在的我,已然是程序员视角,会用矩阵快速幂。
初中的算法是 O(n) 的,高中是数学手段,计算机精度行不通,大学是 O(logn) ,这是友好的。
何为快速幂,就是二分法,算分课讲过这个分治思想,但具体实现可以借助位运算。有些时候,算法的思想和具体实现有不小的差距。
matrix power(int n){
matrix ans=initial;
matrix c;
while(n){
if(n&1) ans=mult(ans,c);
n>>=1;
c=mult(c,c);
}
return ans;
}
算法的原理是显然的,降为对数级。
至于
an
递推转化为矩阵乘法,高代、代组、算分课都讲过。例子是Fibonacci。
我因为要偷懒,只写一个2级矩阵乘法的函数,就这样写了,事实上可以是个2级矩阵乘以列向量。
于是写个矩阵乘法,即可矩阵快速幂。
通常需要取模运算,就每一步对元素取模,如果是负数,可加上模数,以及long long是最后debug的关键。
码这题时我在想去年ACM室友说有一题是矩阵快速幂,忘了怎么写了,最后遗憾地放弃。于是一年里我一直记得快速幂,没想到今年又考到了,这是一种轮回。但不同的是,我进步了。