HDU 5446 Lucas + 中国剩余定理 + 快速乘法
来源:互联网 发布:淘宝密码格式 编辑:程序博客网 时间:2024/05/16 07:53
HDU 5446
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=5446
题意:
求,n,m的范围很大
思路:
Lucas + 中国剩余定理 + 快速乘法。
Lucas定理用来求当n和m很大时的C(n,m)%p(p是素数)。证明网上有,具体公式就是
Lucas(n,m,p) = C(n%p,m%p)*Lucas(n/p,m/p,p)
中国剩余定理用来求同余方程。对方程n的最小解。
设,,则
因为本题数据会爆long long,所以需要用快速乘法,具体见代码,类似快速幂。
源码:
#include <cstdio>#include <cstring>#include <cmath>#include <cstdlib>#include <algorithm>#include <iostream>#include <queue>#include <stack>using namespace std;#define LL long longconst int MAXN = 15;LL prime[MAXN];LL fac[100005], inv[100005];LL lv[MAXN];void exceed_gcd(LL a, LL b, LL &ans, LL &x, LL &y){ if(a < b){ exceed_gcd(b, a, ans, y, x); return; } if(b == 0){ x = 1, y = 0; ans = a; return; } else{ exceed_gcd(b, a % b, ans, y, x); y -= x * (a / b); }}LL ppow(LL a, LL x, LL mod){ LL ans = 1; while(x){// printf("mod = %I64d, a = %I64d, x = %I64d, ans = %I64d\n", mod, a, x, ans); if(x & 1) ans = (ans * a) % mod; a = (a * a) % mod; x >>= 1; } return ans;}LL C(LL n, LL m, LL mod){ if(n < m || n < 0 || m < 0) return 0;// printf("n = %I64d, m = %I64d, fac[n] = %I64d, in[m] = %I64d, inv[n - m] = %I64d\n", n, m, fac[n], inv[m], inv[n - m]); return fac[n] * inv[m] % mod * inv[n - m] % mod;}LL lucas(LL n, LL m, LL mod){// printf("n = %I64d, m = %I64d\n", n, m); if(n < m) {/*printf("n=%I64d,m=%I64d\n",n,m);*/return 0;} if(n == 0 || m == 0) return 1;// printf("n = %I64d, m = %I64d, C = %I64d, lucas = %I64d\n", n, m, C(n % mod, m % mod, mod), lucas(n / mod, m / mod, mod)); return C(n % mod, m % mod, mod) * lucas(n / mod, m / mod, mod) % mod;}LL mul(LL a, LL b, LL mod){ a = (a % mod + mod) % mod; b = (b % mod + mod) % mod; LL ans = 0; while(b){ if(b & 1) ans = (ans + a) % mod; b >>= 1; a <<= 1; a = a % mod; } return ans;}int main(){// freopen("1006.in", "r", stdin); LL n, m, cnt; int t; scanf("%d", &t); while(t--){ scanf("%I64d%I64d%I64d", &n, &m, &cnt); LL M = 1; LL d, y; LL ans = 0; for(int i = 0 ; i < cnt ; i++){ scanf("%I64d", &prime[i]); M *= prime[i]; fac[0] = 1; for(int j = 1 ; j < prime[i] ; j++) fac[j] = fac[j - 1] * j % prime[i]; inv[prime[i] - 1] = ppow(fac[prime[i] - 1], prime[i] - 2, prime[i]); for(int j = prime[i] - 2 ; j >= 0 ; j--) inv[j] = (inv[j + 1] * (j + 1)) % prime[i];// for(int j = 0 ; j < prime[i] ; j++)// printf("fac[%d] = %I64d, inv[%d] = %I64d\n", j, fac[j], j, inv[j]); lv[i] = lucas(n, m, prime[i]); } for(int i = 0 ; i < cnt ; i++){ LL M1 = M / prime[i]; LL M2; exceed_gcd(prime[i], M1, d, y, M2);// printf("i = %d, M1 = %I64d, M2 = %I64d, M = %I64d lv[%d] = %I64d\n", i, M1, M2, M, i, lv[i]);// M2 = (M2 % M + M) % M; ans = (ans + mul(mul(lv[i], M1, M), M2, M)); } ans = (ans % M + M) % M; printf("%I64d\n", ans); } return 0;}
0 0
- HDU 5446 Lucas + 中国剩余定理 + 快速乘法
- HDU 5446 lucas定理 + 中国剩余定理
- HDU 5446 Lucas 中国剩余定理 快速乘
- hdu 5446 lucas + 中国剩余定理 + 快速乘 (快速乘板子,中国剩余定理板子,lucas最新板子)
- HDU 5446 (中国剩余定理 Lucas)
- hdu-5446(中国剩余定理+lucas)
- hdu 5446 Lucas定理,中国剩余定理,处理爆long long 的乘法取模运算
- HDU --- 5446 Unknown Treasure 数论综合【Lucas定理 + 中国剩余定理 + 快速乘 + 思维】
- BZOJ 1951 费马小定理 + Lucas定理 + 乘法逆元 + 中国剩余定理 + 快速幂
- HDU 5446 Unknown Treasure(Lucas定理+中国剩余定理)
- hdu 5446 Unknown Treasure(lucas定理+中国剩余定理)
- hdu 5446 Unknown Treasure(Lucas定理+中国剩余定理)
- HDU 5446 Unknown Treasure Lucas定理+中国剩余定理
- HDU 5446 Unknown Treasure(Lucas定理+中国剩余定理)
- hdu 5446 Unknown Treasure (Lucas定理+中国剩余定理)
- hdu 5446 长春区域赛网络赛1010 Unknown Treasure(lucas定理+中国剩余定理+移位乘法)
- hdu 5446 Unknown Treasure(lucas+中国剩余定理)
- HDU 5446-Unknown Treasure(Lucas+中国剩余定理)
- iOS开发-关于短信验证码倒计时
- 九九乘法表
- iOS开发笔记-url编码保留特殊字符
- 2015 ACM/ICPC Asia Regional Changchun Online hdu5444
- IOS学习 第一天
- HDU 5446 Lucas + 中国剩余定理 + 快速乘法
- Android系统配置数据库注释(settings.db)
- Struts2通配符
- 网络管理之IP计算工具
- [置顶] Linux DM9000网卡驱动程序完全分析 http://blog.csdn.net/ypoflyer/article/details/6209922
- Unity3D之Lightmap详解
- 查看下iPhone模拟器上接收和发送缓冲大小
- 面向对象
- HDU 5456 数位dp