排列数A(n, m)的计算
2015-09-18 08:58
483 查看
排列数是在n个互不相同的数中选出m个能组成的不同次序的排列的方案数。
公式上就等于组合数*全排列,即A(n, m) = n! / (n-m)!
可以说是a1*a2*a3……*am,ai = n-m+i。所以也是一个巨大的数,在计算时通常会要求模P。
举一道题:http://cojs.tk/cogs/problem/problem.php?pid=2037
给出n, m, p,求A(n, m) % p。
虽然m很小,但是鉴于n,p的范围,直接乘会爆,即使是unsigned long long也储存不下36位的数字。一开始的高精度也爆了(高精乘高精爆了表示很不理解TAT),表示无力。
那么为了不使过程量爆long long,我们回归最原始的加法运算,不过用类似快速幂的快速乘来加速这个过程。
还有递归式的。
然而还有某神犇的O(1)快速乘:
原作者本题网页中见。
完整代码:
公式上就等于组合数*全排列,即A(n, m) = n! / (n-m)!
可以说是a1*a2*a3……*am,ai = n-m+i。所以也是一个巨大的数,在计算时通常会要求模P。
举一道题:http://cojs.tk/cogs/problem/problem.php?pid=2037
给出n, m, p,求A(n, m) % p。
虽然m很小,但是鉴于n,p的范围,直接乘会爆,即使是unsigned long long也储存不下36位的数字。一开始的高精度也爆了(高精乘高精爆了表示很不理解TAT),表示无力。
那么为了不使过程量爆long long,我们回归最原始的加法运算,不过用类似快速幂的快速乘来加速这个过程。
L mult(L i, L j, L p){ L ans=0; while(j){ if(j & 1) ans = (ans+i) % p; i = (i+i) % p; j >>= 1; } return ans; }
还有递归式的。
L mult(L i, L j, L p){ if(j <= 1) return i*j; L t = mult(i, j>>1, p); t += t; if(j & 1) t += i; return t % p; }
然而还有某神犇的O(1)快速乘:
原作者本题网页中见。
L mult(L x, L y, L P){ x %= P; y %= P; L k = x*y; L j = (L)(((long double)x*y+0.5)/P); L ans = ( (k - j * P) %P + P) % P; return ans; }
完整代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
typedef long long L;
using namespace std;
L n, m, p;
L mult(L x, L y, L P){ x %= P; y %= P; L k = x*y; L j = (L)(((long double)x*y+0.5)/P); L ans = ( (k - j * P) %P + P) % P; return ans; }
L calc(L l, L r, L p){
L ans = 1;
for(L i = l; i <= r; i++){
ans = mult(ans, i, p);
}
return ans;
}
int main()
{
scanf("%lld %lld %lld", &n, &m, &p);
printf("%lld", calc(n-m+1, n, p));
return 0;
}
相关文章推荐
- 无法访问已释放的对象。 对象名:“WebBrowser”
- Android Https相关完全解析 当OkHttp遇到Https
- JAVA监听器原理
- 数据库的增删
- sublime_text
- HDU - 1171 Big Event in HDU(多重背包或BFS)
- VS2010(VC10)如何查看某个类的变量(函数)使用情况
- 第3周SHH数据结构—【项目1-顺序表的基本运算】
- 第三周项目一顺序表的基本运算
- 阮一峰:网页性能管理详解
- Storm 使用手册
- mac上简单使用redis
- C# Assert Method
- iOS知识点 block-NSFileManager-NSFileHandle
- Java总结篇系列:Java多线程(二)
- 数据库学习相关常用语句
- active mq集群
- Java入门基础之常规的命名方法和变量的值及其引用
- HDU - 2955 Robberies(01背包)
- 笔记