这个题目初看上去是一个排列组合题,而实际上……也是一个排列组合题。
题目描述是:
根据题目给出的递推公式,
S(n, m) = m S(n - 1, m) + S(n - 1, m - 1), for n, m > 0
显然
对于m为偶数,S(n,m)=S(n-1,m-1);
m为奇数,S(n,m)=S(n-1,m)+S(n-1,m-1)=S(n-1,m)+S(n-2,m-2)(m为奇数,则m-2为偶数)
这样的话就没有m这个系数,得到一个递推。
但是问题又来了,这个题目n和m都太大,如果是直接地递推,肯定是承受不住的。
那么就要想想别的办法,在网上看到有人讲到的方法就是根据画图,什么意思呢?
以n为x轴,m为y轴
数形结合,当m为偶数的时候可以变为m-1,当m为奇数的时候可以变为m和m-2,这样就是全部是奇数了。
同时又一个关键的地方需要理解。求S(n,m)就是求又多上条路径从(0,0)到(n,m)仔细理解一下。
这样的话思路又变化到排列组合上来。上面说到所有的偶数m都会变成m-1(奇数),同时对于奇数(n,m)可以变为(n-1,m)和(n-2,m-2)(其实就是两条路)
这样的话就是总共有多少种走法呢。
总共要横着走n-m步,斜着走(即从n,m变为n-2,m-2)(m-1)/2步。
总用要走n-m+(m-1)/2步,
这样总路径数就是C(n-m+(m-1)/2,(m-1)/2)。
于是听过欧拉函数的类似性质就可以迅速地得到所求的答案了呢。
我的代码:
#include <iostream> #include <cstdio> using namespace std; int d,n,m; int count(int x) { return x==0?0:x/2+count(x/2); } int main() { scanf("%d",&d); while (d--) { scanf("%d%d",&n,&m); n-=m,m=(m-1)/2; if (count(n+m)==count(n)+count(m)) puts("1"); else puts("0"); } return 0; }