挑战程序竞赛系列(47):4.1 计数 二项式取模
来源:互联网 发布:风险矩阵图的横纵 编辑:程序博客网 时间:2024/06/07 09:36
挑战程序竞赛系列(47):4.1 计数 二项式取模
详细代码可以fork下Github上leetcode项目,不定期更新。
练习题如下:
- AOJ 2214: Warp Hall
AOJ 2214: Warp Hall
题意参考博文:
http://www.hankcs.com/program/algorithm/aoj-2214-hall-warp.html
思路:
hankcs讲的很清楚,先对虫洞的起始位置排序,接着用一个dp[i]表示到达第i个虫洞起始位置所需要的方案数。
首先,如果不考虑i前面的虫洞,它的方案数有
可以分为两种情况:
- 第i个虫洞的起始位置大于所有前i-1个虫洞的终点位置,那么递推式为:
dp[i] = dp[i] + dp[j] * (j终点到i起点的方案数 - j起点到i起点的方案数) j = 0, 1, ..., i - 1;
- 第i个虫洞的起始位置小于前i-1中某个虫洞的终点位置,那么递推式为:
dp[i] = dp[i] + dp[j] * (0 - j起点到i起点的方案数) j = 0, 1, ..., i - 1;因为从虫洞j不可能回到虫洞i,所以j终点到i起点的方案数为0
ok,有了递推式,现在只要求解cnk模,《挑战》P294有关于CNK取模的算法,但这针对的是p不一定是素数的情况,而此题MOD = 1000000007,是个大素数,所以可以直接取fact的逆,公式为:
代码如下:
import java.io.InputStream;import java.io.PrintWriter;import java.util.ArrayList;import java.util.Collections;import java.util.List;import java.util.Scanner;public class Main{ InputStream is; PrintWriter out; String INPUT = "./data/judge/201709/A2214.txt"; static Scanner in; public static void main(String[] args) throws Exception { in = new Scanner(System.in); new Main().solve(); } static final int MOD = 1000000007; class Wormhole implements Comparable<Wormhole> { int x1; int y1; int x2; int y2; public Wormhole(int x1, int y1, int x2, int y2) { this.x1 = x1; this.x2 = x2; this.y1 = y1; this.y2 = y2; } @Override public int compareTo(Wormhole that) { return this.x1 != that.x1 ? this.x1 - that.x1 : this.y1 - that.y1; } } List<Wormhole> holes; void solve() { init_factorial(); while (true) { int n = in.nextInt(); int m = in.nextInt(); int k = in.nextInt(); if (n == 0 && m == 0 && k == 0) break; holes = new ArrayList<>(); n--; m--; for (int i = 0; i < k; ++i) { int x1 = in.nextInt(); int y1 = in.nextInt(); int x2 = in.nextInt(); int y2 = in.nextInt(); holes.add(new Wormhole(x1 - 1, y1 - 1, x2 - 1, y2 - 1)); } Collections.sort(holes); holes.add(new Wormhole(n, m, n + 1, m + 1)); int[] dp = new int[k + 16]; for (int i = 0; i <= k; ++i) { Wormhole hole = holes.get(i); dp[i] = nck(hole.x1 + hole.y1, hole.x1); for (int j = 0; j < i; ++j) { Wormhole prev = holes.get(j); dp[i] = add(dp[i], mul(dp[j], sub(calc(prev.x2, prev.y2, hole.x1, hole.y1), calc(prev.x1, prev.y1, hole.x1, hole.y1)))); } } System.out.println(dp[k]); } } /************************* mod_fact && mod_comb *****************************/ int add(int a, int b) { return (a + b) % MOD; } int sub(int a, int b) { return (a - b + MOD) % MOD; } int mul(long a, long b) { return (int) (((a * b)) % MOD); } int[] fact = new int[200010]; void init_factorial() { fact[0] = 1; for (int i = 1; i < 200000; ++i) { fact[i] = mul(fact[i - 1], i); } } class GCD { int d; int x; int y; public GCD(int d, int x, int y) { this.d = d; this.x = x; this.y = y; } } GCD extgcd(int a, int b) { if (b == 0) return new GCD(a, 1, 0); else { GCD p = extgcd(b, a % b); GCD ans = new GCD(0, 0, 0); ans.d = p.d; ans.x = p.y; ans.y = p.x - (a / b) * p.y; return ans; } } int inv(int a, int m) { GCD p = extgcd(a, m); if (p.d != 1) return -1; return (p.x % m + m) % m; } int nck(int n, int k) { return mul(mul(fact[n], inv(fact[n - k], MOD)), inv(fact[k], MOD)); } int calc(int x1, int y1, int x2, int y2) { if (x2 < x1 || y2 < y1) return 0; return nck(x2 - x1 + y2 - x1, x2 - x1); }}
测试用例都过了,但放在AOJ上就RE,总感觉测试接口有问题。。。
阅读全文
0 0
- 挑战程序竞赛系列(47):4.1 计数 二项式取模
- 挑战程序竞赛系列(45):4.1Polya 计数定理(1)
- 挑战程序竞赛系列(46):4.1Polya 计数定理(2)
- 挑战程序竞赛系列(44):4.1计数 欧拉函数
- 挑战程序竞赛系列(41):4.1中国剩余定理
- 挑战程序竞赛系列(43):4.1矩阵 高斯消元
- 挑战程序竞赛系列(38):4.1模运算的世界(1)
- 挑战程序竞赛系列(39):4.1模运算的世界(2)
- 挑战程序竞赛系列(40):4.1模运算的世界(3)
- 挑战程序竞赛系列(42):4.1模运算的世界(4)
- 挑战程序竞赛系列(81):4.3 LCA(1)
- 挑战程序竞赛系列(82):4.3 LCA(2)
- 挑战程序竞赛系列(1):2.3动态规划
- 挑战程序竞赛系列(4):2.1深度优先搜索
- 挑战程序竞赛系列(5):2.1广度优先搜索
- 挑战程序竞赛系列(6):2.1穷尽搜索
- 挑战程序竞赛系列(9):2.4优先队列
- 挑战程序竞赛系列(10):2.4并查集
- 防止表单重复提交
- java按照字节长度获取字符串长度
- 特征缩减系数的理解等 岭回归 lasso
- [LibreOJ β Round #4]求和
- JS中的函数
- 挑战程序竞赛系列(47):4.1 计数 二项式取模
- git 操作文档
- 2017-09-04考试情况总结
- 框架漫谈之hibernate(二)hibernate配置以及入门案例
- Java--重载--重写
- Tomcat优化
- loadrunner Web_类函数之web_button()
- ♪ ♩ ♫ 海的声音-《这个世界不是因为你而存在-谦》
- linux安装配置zookeeper-3.4.10