第二类斯特林数-BINSTIRL - Binary Stirling Numbers

· · 题解

前言:双倍经验。

题目大意

求第二类斯特林数 \begin{Bmatrix}n \\ m\end{Bmatrix}\bmod2 的值,也就是判断它的奇偶性。

思路

啊数学题,真快乐。

首先把递推式列出来,\begin{Bmatrix}n \\ m\end{Bmatrix}=\begin{Bmatrix}n-1 \\ m-1\end{Bmatrix}+m\cdot \begin{Bmatrix}n-1 \\ m\end{Bmatrix}。然后分类讨论一下 m 的奇偶性。

\begin{cases} \begin{Bmatrix}n-1 \\ m-1\end{Bmatrix}\pmod 2 ,2\mid m \\ \left(\begin{Bmatrix}n-1 \\ m-1\end{Bmatrix}+\begin{Bmatrix}n-1 \\ m\end{Bmatrix}\right)\pmod 2 ,2\nmid m \\ \end{cases}

然后转换一下,可以变为:

2\mid j 时,\begin{Bmatrix}i \\ j\end{Bmatrix} 会转移到 \begin{Bmatrix}i+1 \\ j+1\end{Bmatrix}\begin{Bmatrix}i+1 \\ j\end{Bmatrix}

2\nmid j 时,\begin{Bmatrix}i \\ j\end{Bmatrix} 会转移到 \begin{Bmatrix}i+1 \\ j+1\end{Bmatrix}

就很类似在一个平面直角坐标系里跑,从 (0,0)(n,m) 的方法再模 2 的问题。那 \begin{Bmatrix}i+1 \\ j\end{Bmatrix} 就可以看作往右走,\begin{Bmatrix}i+1 \\ j+1\end{Bmatrix} 为往右上走。又因为只有往右和右上两周方向,所以只能走 n 步,其中有 m 步右上,n-m 步右。

然后因为只能在奇数的情况下向右转移,也就是只有 \lfloor{\dfrac{m+1}{2}}\rfloor 次。那把这个带回去,就是有 n-m 个球,放到 \lfloor{\dfrac{m+1}{2}}\rfloor 个盒子里的问题,即 \dbinom{n-m+\lfloor{\dfrac{m+1}{2}}\rfloor-1}{\lfloor{\dfrac{m+1}{2}}\rfloor-1}

也就把斯特林数的奇偶性转化为了组合数的奇偶性问题。

然后考虑组合数的奇偶性问题,虽然可能不是这道题的重点,但还是用我这种愚蠢的思维证一下。因为 Lucas 定理告诉了我们在 p 进制下的两数

x=(\overline {x_0x_1\cdots x_k})_p y=(\overline {y_0y_1\cdots y_k})_p

则有

\dbinom{x}{y}\equiv\prod_{i=0}^k\dbinom{x_i}{y_i} \pmod p

而对于本题,p=2,带进去就可以发现如果 \dbinom{x}{y} 要为奇数,则其中的 \dbinom{x_i}{y_i} 必须不出现 0。而我们又知道,\dbinom{0}{1}=0,所以对于任意的 x_iy_i,不会出现 x_i=0y_i=1 的情况。如果出现的话,当 xy 做按位与运算的时候,答案就不可能为 y,即 x\&y\ne y。相反,如果未出现上述情况的话,即当 \dbinom{x}{y} 为奇数时,会有 x\&y=y

那就得到了组合数的奇偶性的公式:

对于 \dbinom{a}{b},当且仅当 a\&b=b2\nmid \dbinom{a}{b}

那把这个带回去,就可以直接写代码了。

然后注意特判。

code

/*
ID: enderch1    
PROG:
LANG: C++
*/
#include<iostream>
#include<cstdio>
#define change_max(a,b) a=max(a,b)
#define change_min(a,b) a=min(a,b)
#define int long long
using namespace std;

int read()
{
    int s=0,w=1;
    char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') {s=s*10+ch-'0';ch=getchar();}
    return s*w;
}
void solve()
{
    int T=read();
    while(T--)
    {
        int n=read(),m=read();
        int temp=(m+1)/2;
        if((!n)&&(!m)) puts("1");
        else if((!n)||(!m)||n<m) puts("0");
        else if(((n-m+temp-1)&(temp-1))==(temp-1)) puts("1");
        else puts("0");
    }
}
signed main()
{
    solve();
    return 0;
}

放在最后:猪马好闪,拜谢猪马。

@cqbzlzm

The End