题目大意
聪明的小蛮提出一个有趣的问题:有多少种不同的传球方法可以使得从小蛮手里开始传的球,传了m次以后,又回到小蛮手里。两种传球方法被视作不同的方法,当且仅当这两种方法中,接到球的同学按接球顺序组成的序列是不同的。比如有三个同学1号、2号、3号,并假设小蛮为1号,球传了3次回到小蛮手里的方式有1->2->3->1和1->3->2->1,共2种。
题面来自洛谷
思路
设f[i][j]为传j个球后到i的方案数,显然f[1][0]=1,那么其他部分有:
- 当i=1时,f[i][j]=f[n][j-1]+f[2][j-1]
- 当i=n时,f[i][j]=f[1][j-1]+f[n-1][j-1]
- 其他情况,f[i][j]=f[i-1][j-1]+f[i+1][j-1]
证明:
因为每一个人的球只能从左边的人或右边的人传过来,所以我们
f
[
i
]
[
j
]
=
f
[
i
−
1
]
[
j
−
1
]
+
f
[
i
+
1
]
[
j
−
1
]
f[i][j]=f[i-1][j-1]+f[i+1][j-1]
f[i][j]=f[i−1][j−1]+f[i+1][j−1]
又因为1和n站在一起,所以
f
[
n
]
[
j
]
=
f
[
1
]
[
j
−
1
]
+
f
[
n
−
1
]
[
j
−
1
]
,
f
[
1
]
[
j
]
=
f
[
n
]
[
j
−
1
]
+
f
[
2
]
[
j
−
1
]
f[n][j]=f[1][j-1]+f[n-1][j-1],f[1][j]=f[n][j-1]+f[2][j-1]
f[n][j]=f[1][j−1]+f[n−1][j−1],f[1][j]=f[n][j−1]+f[2][j−1]
证毕.
证明来自《ybtoj高效进阶》
code:
#include <iostream>
using namespace std;
long long a[31][31];
int n, m;
int main() {
cin >> n >> m;
a[1][0] = 1;
for (int j = 1; j <= m; j++) {
for (int i = 1; i <= n; i++) {
if (i == 1)
a[i][j] = a[i + 1][j - 1] + a[n][j - 1];
else if (i == n)
a[i][j] = a[i - 1][j - 1] + a[1][j - 1];
else
a[i][j] = a[i - 1][j - 1] + a[i + 1][j - 1];
}
}
cout << a[1][m];
return 0;
}