C - Binary Stirling Numbers
Time Limit:1000MS Memory Limit:10000KB 64bit IO Format:%I64d & %I64u
Submit
Status
Practice
POJ 1430
Description
The Stirling number of the second kind S(n, m) stands for the number of ways to partition a set of n things into m nonempty subsets. For example, there are seven ways to split a four-element set into two parts:
{1, 2, 3} U {4}, {1, 2, 4} U {3}, {1, 3, 4} U {2}, {2, 3, 4} U {1}
{1, 2} U {3, 4}, {1, 3} U {2, 4}, {1, 4} U {2, 3}.
There is a recurrence which allows to compute S(n, m) for all m and n.
S(0, 0) = 1; S(n, 0) = 0 for n > 0; S(0, m) = 0 for m > 0;
S(n, m) = m S(n - 1, m) + S(n - 1, m - 1), for n, m > 0.
Your task is much "easier". Given integers n and m satisfying 1 <= m <= n, compute the parity of S(n, m), i.e. S(n, m) mod 2.
Example
S(4, 2) mod 2 = 1.
Task
Write a program which for each data set:
reads two positive integers n and m,
computes S(n, m) mod 2,
writes the result.
Output
The output should consist of exactly d lines, one line for each data set. Line i, 1 <= i <= d, should contain 0 or 1, the value of S(ni, mi) mod 2.
过了这题,我很兴奋,很久都没有这种感觉了。真的很舒服,不过这题我想了很久,数论的类型,的确有些难想。
好了,不多说了,说说这题到底怎么个解法吧!此题解法都是自己一步一步推过来的,希望对大家有启发。
首先由于%2的操作,我想到了f(n,m) = s(n,m)%2,假设一个f函数。于是s(n,m) = m * s(n-1,m)+ s(n-1,m-1) ==>
f(n,m) = s(n-1,m-1) (m为偶数); f(n,m) = f(n-1,m) + f(n-1,m-1)(m为奇数)。这样就可以将m给去掉,最后就是计算f(n,m)%2即可,必须想到怎么样得到f(n,m)。
怎么得到呢?这一步是比较难想的。我用递推,推了很久都不行,因为n,m实在太大了。于是我想到了先画个图,希望通过图形来表示它们的递推关系,果真很管用,我找到了。x轴表示n方向,y轴表示m方向,那么我可以看出其实就找从(0,0)点到(n,m)点有多少条路径,就是f(n,m) 的值了。如果大家将图画出来后,然后通过上式去找,我相信会找到公式了,最后其实得到的是一个组合 求出 f(n,m) = C(n-m, (m-1)/2)。不会很难找,大家就画画吧。
简化就是求C(n,m)%2 ,就是求C(n,m)的奇偶了。怎么求呢,这又是一个难点。C(n,m) = m!/(n!*(m-n)!){这个大家都知道的},这里就是要靠数学感觉了,我直接就想到了肯定和2因子有关,于是就得到这样一个结论,如果分子2因子的个数= 分母2因子的个数,那么就为奇数;否则就为偶数.。大家多想想,如果有些疑问,给我留言,现在就不在这里多说了。
相信大家如果看来上面且明白后,这个题AC就是2分钟内了。
#include <iostream>
using namespace std;
__int64 f(__int64 x)//计算x! 2的因子数目
{
__int64 t =0;
while(x)
{
x /= 2;
t += x;
}
return t;
}
int main()
{
int cas;
__int64 n,m;
scanf("%d",&cas);
while(cas)
{
cas --;
cin>>n>>m;
n -= m;
m = (m-1)/2;
if(f(n+m) == f(n)+ f(m))
printf("1\n");
else
printf("0\n");
}
return 0;
}