挑战全网最快!!
做法一O(N)
直接递推, d p [ i ] [ j ] dp[i][j] dp[i][j]表示Tiger在换了i次车时位于j的方案数,最后输出 d p [ n ] [ E ] dp[n][E] dp[n][E]
由于这是2002年的题,所以用现在的评测机O(N)也能过
做法二O(8^3logN)
矩阵乘法,转移矩阵如下
0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 |
---|---|---|---|---|---|---|---|
1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 |
0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 |
0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 |
1 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
不说了。
做法三O(5^3logN)
由于这个图左右是对称的,所以B和H,C和G,D和F的方案数都是一样的,所以只需要存5个点就好了。
转移矩阵就不放了,和做法二类似。
做法四O(2^2logN)
由于此题图形都是一样的,所以最终答案是有通项公式的!
然后我们先写出递推式:
- a ( 0 ) = 1 a(0)=1 a(0)=1
- a ( n ) = 2 b ( n − 1 ) a(n)=2b(n-1) a(n)=2b(n−1)
- b ( n ) = a ( n − 1 ) + c ( n − 1 ) b(n)=a(n-1)+c(n-1) b(n)=a(n−1)+c(n−1)
- c ( n ) = b ( n + 1 ) + d ( n − 1 ) c(n)=b(n+1)+d(n-1) c(n)=b(n+1)+d(n−1)
- d ( n ) = c ( n − 1 ) d(n)=c(n-1) d(n)=c(n−1)
- e ( n ) = 2 d ( n − 1 ) e(n)=2d(n-1) e(n)=2d(n−1)
写出生成函数(OGF),和生成函数之间的5个方程
- A ( z ) = 2 z B ( z ) + 1 A(z)=2zB(z)+1 A(z)=2zB(z)+1
- B ( z ) = z A ( z ) + z C ( z ) B(z)=zA(z)+zC(z) B(z)=zA(z)+zC(z)
- C ( z ) = z B ( z ) + z D ( z ) C(z)=zB(z)+zD(z) C(z)=zB(z)+zD(z)
- D ( z ) = z C ( z ) D(z)=zC(z) D(z)=zC(z)
- E ( z ) = 2 z D ( z ) E(z)=2zD(z) E(z)=2zD(z)
解关于
A
(
z
)
,
B
(
z
)
,
C
(
z
)
,
D
(
z
)
,
E
(
z
)
A(z),B(z),C(z),D(z),E(z)
A(z),B(z),C(z),D(z),E(z),含参数
z
z
z的五元一次方程组,得:
E
(
z
)
=
2
z
4
1
−
4
z
2
+
2
z
4
E(z)=\frac{2z^4}{1-4z^2+2z^4}
E(z)=1−4z2+2z42z4
因式分解:
k
1
=
2
+
2
,
k
2
=
2
−
2
k_1=2+\sqrt2,k_2=2-\sqrt2
k1=2+2,k2=2−2
E
(
z
)
=
2
z
4
(
1
−
k
1
z
2
)
(
1
−
k
2
z
2
)
E(z)=\frac{2z^4}{(1-k_1z^2)(1-k_2z^2)}
E(z)=(1−k1z2)(1−k2z2)2z4
我们来好好理解一下这个式子:
- 分子是个最低次为4次的多项式,因为从A到E最少要换乘4次
- 分母中分解后的两个多项式中每项的次数皆为偶数因为从A到E换乘的次数必然为偶数,如果是奇数那么肯定到不了E(染色法可证)
所以我们可以直接略过 e ( 2 n + 1 ) e(2n+1) e(2n+1)(这些全是0),只用计算 e ( 2 n ) e(2n) e(2n)即可。
让我们直接写出
e
(
2
n
)
e(2n)
e(2n)的生成函数(OGF)
F
(
z
)
F(z)
F(z)
F
(
z
)
=
2
z
2
(
1
−
k
1
z
)
(
1
−
k
2
z
)
F(z)=\frac{2z^2}{(1-k_1z)(1-k_2z)}
F(z)=(1−k1z)(1−k2z)2z2只需要满足
F
(
z
2
)
=
E
(
z
)
F(z^2)=E(z)
F(z2)=E(z)即可
定义 f ( n ) = e ( 2 n ) f(n)=e(2n) f(n)=e(2n),则 f ( 1 ) = f ( 0 ) = 0 f(1)=f(0)=0 f(1)=f(0)=0(因为只通过2次换乘到不了E)
所以直接把
z
2
z^2
z2从分母中提出来:
F
(
z
)
=
z
2
2
(
1
−
k
1
z
)
(
1
−
k
2
z
)
F(z)=z^2\frac{2}{(1-k_1z)(1-k_2z)}
F(z)=z2(1−k1z)(1−k2z)2
再根据有理生成函数的一般展开定理:
f
(
n
+
2
)
=
a
1
∗
k
1
n
+
a
2
∗
k
2
n
f(n+2)=a_1*{k_1}^n+a_2*{k_2}^n
f(n+2)=a1∗k1n+a2∗k2n
已知两个等式(一个显而易见,一个是样例给的):
f
(
2
)
=
2
,
f
(
3
)
=
8
f(2)=2,f(3)=8
f(2)=2,f(3)=8代入
f
(
n
+
2
)
=
a
1
∗
k
1
n
+
a
2
∗
k
2
n
f(n+2)=a_1*{k_1}^n+a_2*{k_2}^n
f(n+2)=a1∗k1n+a2∗k2n就能求出系数
a
1
,
a
2
a_1,a_2
a1,a2了!!胜利在望
解得 a 1 = 1 + 2 , a 2 = 1 − 2 a_1=1+\sqrt2,a_2=1-\sqrt2 a1=1+2,a2=1−2
所以最后的通项公式为:
f
(
n
+
2
)
=
(
1
+
2
)
(
2
+
2
)
n
+
(
1
−
2
)
(
2
−
2
)
n
f(n+2)=(1+\sqrt2)(2+\sqrt2)^n+(1-\sqrt2)(2-\sqrt2)^n
f(n+2)=(1+2)(2+2)n+(1−2)(2−2)n
由于两个可以表示成
a
2
+
b
a\sqrt2+b
a2+b的数相乘还是可以表示成
a
2
+
b
a\sqrt2+b
a2+b,所以把原来的乘法改成4次乘法然后快速幂就可以了。
上代码!
#include<bits/stdc++.h>
using namespace std;
namespace fastio{
template<typename tn> void read(tn &a){
tn x=0,f=1;char c=' ';
for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
for(;isdigit(c);c=getchar() ) x=x*10+c-'0';
a=x*f;
}
template<typename tn> void print(tn a){
if(a<0) putchar('-'),a=-a;
if(a>9) print(a/10);
putchar(a%10+'0');
}
};
using namespace fastio;
const int mod=1000;
struct num{
int a,b;
num operator *(const num x)const{
num ret;
ret.b=(2*x.a*a+x.b*b)%mod;
ret.a=(x.a*b+x.b*a)%mod;
return ret;
}
num operator +(const num x)const{
num ret;
ret.a=(x.a+a)%mod;
ret.b=(x.b+b)%mod;
return ret;
}
};
int n;
num poww(num a,int b){
num ans=(num){0,1};
while(b){
if(b&1) ans=ans*a;
a=a*a;
b>>=1;
}
return ans;
}
int main(){
read(n);
if(n&1){
puts("0");
return 0;
}
n>>=1;
n-=2;
if(n<0){
puts("0");
return 0;
}
num ans=(num){1,1}*poww((num){1,2},n);
printf("%d\n",ans.b*2%mod);
return 0;
}
提交!
然而并没有比矩阵乘快到那里去(我杀我自己)