51nod 1829 函数 (第二类斯特林数+逆元) 屎上最详细题解
来源:互联网 发布:达盖尔先锋团 知乎 编辑:程序博客网 时间:2024/06/04 20:06
传送门:51nod 1829
题目大意:
对于本蒟蒻来说,做这道题也是绞尽乳汁,啊,呸……绞尽脑汁。这道题所用到的知识点很多,希望下面我可以把它说明白,涉及的知识点较多,希望大家耐心阅读。
前置技能:
1.第二类斯特林数。第二类Stirling数 S(n,m) 表示将 n 个不同的元素分成 m 个非空集合的方案数。
2.逆元。或者说乘法逆元,除以一个数取模等于乘以这个数的逆元取模,即设 c 为 b 的逆元,则 (a/b)%m=(a*c)%m 。为什么要用逆元呢?直接相除取模不就可以了吗?如果仅有一步的时候是正确的,但是如果对一个已经取模的数再除以 b 取模呢?答案就可能不正确了,这时候就需要用逆元来做。
3.同余模定理。这里只说一下乘法公式,其他的类似:若 n=a*b ,则 n%m = ( a%m * b%m )%m .
思路:
所谓映射,就是对于 B 中任何一个元素在 A 中都有元素与之对应,而 A 中的一个元素只能对应 B中的一个元素。
看到这道题的时候有没有想到第二类斯特林数呢?也就是将 n 个不同的元素分成 m 个非空集合的方案数。当然由于分成的集合是无差别的,但是映射的时候是有差别的,所以还要乘以 B 中元素的全排列,即 m! 。
之前只知道第二类斯特林数有个递推公式:
其中 (m-i)^n % mod 好说,可以用快速幂取模解决。C(m,i) 取模时要注意由于组合数公式用到了除法,所以这里要用逆元,即除以一个数取模等于乘以这个数的逆元取模。
如上图,计算 C(m,n) 要计算出 m! 以及 n! * (m-n)! 模 mod 的逆元,可以分别求 n! 模 1e9+7 的逆元和 (m-n)! 模 mod 的逆元。由于 n! 和 (m-n)! 都和 mod 互质并且 mod 为质数,所以可以用费马定理求逆元为: n! ^ (mod-2) 和 (m-n)! ^ (mod-2)。 mod = 1e9+7.
我们另 fac[i] 表示 i 的阶乘,inv[i] 表示 i 的阶乘的逆元,另 mod=1e9+7,则 fac[i+1] 的逆元为 fac[i+1] ^ (mod-2) ,即 (fac[i]^(mod-2) * (i+1)^(mod-2))% mod,而 fac[i] 的逆元为 fac[i]^(mod) ,所以 inv[i+1] = ( inv[i] * (i+1)^(mod-2) ) % mod . 而我们知道 inv[1] = 1^(mod-2) = 1 ,所以就可以根据公式得到每个阶乘的逆元了。
然鹅……由于以上逆元的公式包含求幂操作,所以会超时Orz……所以我们可以逆着推, inv[i] = ( inv[i+1] / (i+1)^(mod-2) ) % mod , 要除以(i+1)^(mod-2),就等于乘以它的逆元……由于逆元是相互的,即 i+1 模 mod 的逆元为(i+1)^(mod-2) ,所以(i+1)^(mod-2) 模 mod 的逆元为 i+1。 inv[i]=( inv[i+1] * (i+1) ) % mod.
然后求组合数解决了,求快速幂也解决了,就可以敲代码了……本来想简单的解释清楚的,没想到又说了这么多。。。真心搞不懂大牛们都是怎么想出的题解……果真是自己弱,Orz……
代码:
#include<stdio.h> #include<string.h>#define MAXN 1000010typedef long long LL;LL mod=1e9+7;LL fac[MAXN],inv[MAXN]; //fac表示阶乘,inv表示阶乘的逆元 LL pow(LL a,LL b){ //快速幂取模 LL r=1,base=a;while(b){if(b&1) r=r*base%mod;base=base*base%mod;b>>=1;}return r;}void init(){ //求每个数的阶乘和阶乘的逆元 int i;fac[0]=1;for(i=1;i<MAXN;i++) //求阶乘 fac[i]=fac[i-1]*i%mod;inv[MAXN-1]=pow(fac[MAXN-1],mod-2); //根据费马定理求最后一个数阶乘的逆元 for(i=MAXN-2;i>=0;i--) //根据公式求每个阶乘的逆元 inv[i]=inv[i+1]*(i+1)%mod;/* 因为用到快速幂,会超时 inv[1]=1;for(i=2;i<MAXN;i++)inv[i]=(inv[i-1]*pow(i,mod-2))%mod;*/}LL C(LL n,LL m){ //根据组合数公式求组合数 if(m>n) return 0;if(m==0) return 1;return fac[n]*inv[m]%mod * inv[n-m]%mod; //利用了同余模定理 }int main(){init();int i,n,m,e;LL ans=0;e=1;scanf("%d%d",&n,&m);for(i=0;i<=m;i++){ //结果是很多数之和 ans+=C(m,i)*pow(m-i,n)%mod*e;ans%=mod;e*=-1;}printf("%lld\n",(ans+mod)%mod);//防止是负数 return 0;}
- 51nod 1829 函数 (第二类斯特林数+逆元) 屎上最详细题解
- 51 nod 乘法逆元
- 51nod 1256 乘法逆元
- 51nod 1256 乘法逆元
- 51 nod 1256 乘法逆元
- 51nod:1256 乘法逆元
- 51nod-【1256 乘法逆元】
- 51nod 1013【快速幂+逆元】
- 51nod 1256 乘法逆元
- [51NOD]1256 乘法逆元
- 51Nod 1256 乘法逆元
- 51nod 1256 乘法逆元
- 51nod 1256 乘法逆元
- 51nod 5126乘法逆元
- 51Nod 1256 乘法逆元
- 51nod 1256 乘法逆元
- 51nod 1256 乘法逆元
- 51Nod 1256:乘法逆元
- autoMonkey框架原理与应用(三):Monkey测试的日志分析
- RxJava+Retrofit 封装
- Item 4:确定对象被使用前已先被初始化【effective C++读书笔记】
- T-SQL编程基础
- Cocos2dx游戏开发需要用到哪些软件
- 51nod 1829 函数 (第二类斯特林数+逆元) 屎上最详细题解
- 利用贪心算法计算袋鼠过河问题
- 11.11面试
- JSP 四大通信作用域
- 论C++11 中vector的N种遍历方法
- HALCON轮廓整理
- webpack实战——(1)安装及命令行
- 算法学习之路:动态规划-钢条切割-java实现
- 进制转换问题(java)