题目描述

n个人在w*h的监狱里面想要逃跑,已知他们的同伙在坐标(bi,h)接应他们,他们现在被关在(ai,1)现在他们必须要到同伙那里才有逃出去的机会,这n个人又很蠢只会从(x,y)->(x+1,y),(x,y+1)并且这他们走过的路径不能相交如果相交第一个经过后就会有第二个人经过时候就会有一名狱警在那等他,第二个人就会被抓,假设他们不会同时踩到某个格子,那么他们的逃跑路线有多少不同的方案数。如果两个方案不同那么存在一个人踩的格子至少有一个是另外一个方案的没踩过

输入

第一行一个t(t<=20)表示测试样例 
第二行两个3个正整数n,w,h(n<=100,w,h<=1e9) 
接下来n行每行两个整数 
ai,bi(ai,bi<=w) 

输出

输出一个整数表示答案最终结果取膜109*1000003

样例输入

1
2 4 2
1 2
3 4

样例输出

4

思路:

这里有一个结论,n个起点到n个终点的不相交路径的种数为:每个起点到每个终点的可能数组成的n*n的矩阵的行列式。

即求上矩阵行列式,其中e(ai,bi)代表从ai起点到bi终点的可能路径数量,行列式求解用高斯消元。

显然现在的问题是求解e。显然e(a[i],b[j])= (h - 1 + b[j] - a[i], b[j] - a[i])或者0。

但是a、b、h范围均为1e9,那么求解组合数需要用到Lucas定理,但是mod = 109 * 1000003,显然是个合数,那么需要先质因数分解(显然分好了),然后中国剩余定理合并。

参考:

HDU 5852:Intersection is not allowed!(行列式+逆元求组合数)

hdu 5446 Unknown Treasure(Lucas定理+中国剩余定理)

Update:被工程卡时间卡的的心态崩了,优化了一些地方:

ll w = M / m[i];
d = exgcd(m[i], w, x, y);
ret = (ret + modmul(modmul(y, w, M), a[i], M) ) % M;

这里很显然不用每次都求w的逆元,因为w确定m[i]确定,直接小费马求出来保存就行。

还有很多取模都可以去掉,因为不论是阶乘还是阶乘的逆元,我们打表的时候都是%1e6+3,也就是说(1e6+3)^3也就18位左右,long long最大19位,似乎可以去掉(雾...

然后一些开long long开成int,就能慢慢卡进1000ms了(逃

admin标程跑的速度比我快了3倍...不知道什么操作

代码(新):

#include<set>
#include<map>
#include<stack>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
typedef long long ll;
using namespace std;
const int maxn = 1e5 + 10;
const int seed = 131;
const ll MOD = 109 * 1000003;
const int INF = 0x3f3f3f3f;
int a[105], b[105];
ll e[105][105];
ll fac[2][1000010], inv[2][1000010];
ll modmul(ll a, ll b, ll p){ll ret = 0;while(b) {if(b & 1) ret = ret + a;if(ret >= p) ret -= p;a <<= 1;if(a >= p) a -= p;b >>= 1;}return ret;
}
ll pmul(ll a, ll b, ll p){ll ans = 1;a %= p;while(b){if(b & 1) ans = ans * a % p;a = a * a % p;b >>= 1;}return ans;
}
ll C(ll n, ll m, ll p, int i){if(m > n) return 0;return fac[i][n] * inv[i][m] * inv[i][n - m] % p;
}
ll Lucas(ll n, ll m, ll p, int i){if(m == 0) return 1;if(n < p && m < p) return C(n, m, p, i);return C(n % p, m % p, p, i) * Lucas(n / p, m / p, p, i) % p;
}
ll mm[2] = {56, 486240};
ll remainder(ll a[], ll m[], int len){ll x, y, ret = 0;ll M = MOD;for (int i = 0; i < len; i++){ll w = M / m[i];ret = (ret + a[i] * mm[i] * w) % M;}return ret;
}
ll guass(int n, ll p){ll ans = 1, f = 1;for(int i = 1; i <= n; i++){for(int j = i + 1; j <= n; j++){int x = i, y = j;while(e[y][i]){ll t = e[x][i] / e[y][i];for(int k = i; k <= n; k++)e[x][k] = (e[x][k] - e[y][k] * t % p) % p;swap(x,y);}if(x != i){for(int k = 1; k <= n; k++)swap(e[i][k], e[j][k]);f = -f;}}ans = ans * e[i][i] % p;if(ans == 0) return 0;}return (ans * f + p) % p;
}
void init(int x, int n){fac[x][0] = 1;for (ll i = 1; i < n; i++) fac[x][i] = fac[x][i - 1] * i % n;inv[x][n - 1] = pmul(fac[x][n - 1], n - 2, n);for (ll i = n - 2; i >= 0; i--) inv[x][i] = inv[x][i + 1] * (i + 1) % n;
}
ll lucas[2];
ll pp[2] = {109, 1000003};
ll solve(ll n, ll m){ll ret;for(int i = 0; i < 2; i++){lucas[i] = Lucas(n, m, pp[i], i);}ret = remainder(lucas, pp, 2);return ret;
}
int main(){init(0, 109);init(1, 1000003);int t;scanf("%d", &t);while(t--){ll n, w, h;scanf("%lld%lld%lld", &n, &w, &h);for(int i = 1; i <= n; i++)scanf("%d%d", &a[i], &b[i]);for(int i = 1; i <= n; i++){for(int j = 1; j <= n; j++){if(b[j] >= a[i]){e[i][j] = solve(h - 1 + b[j] - a[i], b[j] - a[i]);}else e[i][j] = 0;}}printf("%lld\n", guass(n, MOD));}return 0;
}

代码:

#include<set>
#include<map>
#include<stack>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
typedef long long ll;
using namespace std;
const int maxn = 1e5 + 10;
const int seed = 131;
const ll MOD = 109 * 1000003;
const int INF = 0x3f3f3f3f;
ll a[maxn], b[maxn];
ll e[105][105];
ll prime[maxn], p[maxn], pn;
ll fac[2][1000010];
ll pmul(ll a, ll b, ll p){ll ans = 1;while(b){if(b & 1) ans = ans * a % p;a = a * a % p;b >>= 1;}return ans;
}
ll modmul(ll a, ll b, ll p) {ll ret = 0;while(b) {if(b & 1) ret = (ret + a) % p;a = (a + a) % p;b >>= 1;}return ret;
}
ll Lucas(ll n, ll m, ll p, int i) {ll ret=1;while(n && m) {ll a = n%p, b = m%p;if(a<b) return 0;ret = (ret * fac[i][a] * pmul(fac[i][b]*fac[i][a - b] % p, p-2, p)) % p;n/=p;m/=p;}return ret;
}ll exgcd (ll a, ll b, ll &x, ll &y) {if (!b) {x = 1, y = 0;return a;}int ans = exgcd ( b , a % b , y , x );y -= a / b * x;return ans;
}
ll remainder(ll a[], ll m[], int len) {ll d, x, y, ret = 0;ll M = 1;for (int i = 0; i < len; i++) M *= m[i];for (int i = 0; i < len; i++) {ll w = M / m[i];d = exgcd(m[i], w, x, y);ret = (ret + modmul(modmul(y, w, M), a[i], M) ) % M;}return (ret + M) % M;
}
ll guass(int n, ll MOD){ll ans = 1, f = 1;for(int i = 1; i <= n; i++){for(int j = i + 1; j <= n; j++){int x = i, y = j;while(e[y][i]){ll t = e[x][i] / e[y][i];for(int k = i; k <= n; k++)e[x][k] = (e[x][k] - e[y][k] * 1LL * t % MOD) % MOD;swap(x,y);}if(x != i){for(int k = 1; k <= n; k++)swap(e[i][k], e[j][k]);f = -f;}}ans = ans * e[i][i] % MOD;if(ans == 0) return 0;}return (ans * f + MOD) % MOD;
}
void init(){memset(prime, 0, sizeof(prime));pn = 0;for(ll i = 2; i < maxn; i++){if(!prime[i]){p[pn++] = i;for(ll j = i * i; j < maxn; j += i)prime[i] = 1;}}fac[0][0] = 1;for(int i = 1; i <= 109; i++){fac[0][i] = (fac[0][i-1]*i) % 109;}fac[1][0] = 1;for(ll i = 1; i <= 1000003; i++){fac[1][i] = (fac[1][i-1]*i) % 1000003;}
}
ll solve(ll n, ll m){ll ret;ll lucas[2];ll p[2] = {109, 1000003};for(int i = 0; i < 2; i++){lucas[i] = Lucas(n, m, p[i], i);}return ret = remainder(lucas, p, 2);
}
int main(){init();int t;scanf("%d", &t);while(t--){ll n, w, h;scanf("%lld%lld%lld", &n, &w, &h);for(int i = 1; i <= n; i++)scanf("%lld%lld", &a[i], &b[i]);for(int i = 1; i <= n; i++){for(int j = 1; j <= n; j++){if(b[j] >= a[i]){e[i][j] = solve(h - 1 + b[j] - a[i], b[j] - a[i]);}else e[i][j] = 0;}}printf("%lld\n", guass(n, MOD));}return 0;
}

转载于:https://www.cnblogs.com/KirinSB/p/10031394.html

FJNU2018低程A 逃跑路线(Lucas + 中国剩余定理 + LGV定理)题解相关推荐

  1. 中国剩余定理(孙子定理)的证明和c++求解

    <孙子算经>里面的"物不知数"说的是这样的一个题目:一堆东西不知道具体数目,3个一数剩2个,5个一数剩3个,7个一数剩2个,问一共有多少个. 书里面给了计算过程及答案: ...

  2. 中国剩余定理(孙子定理)(精华详细版!)

    问题:今有物不知其数,三三数之剩二,五五数之剩三,七七数之剩二.问物几何? 简单点说就是,存在一个数x,除以3余2,除以5余三,除以7余二,然后求这个数.上面给出了解法.再明白这个解法的原理之前,需要 ...

  3. 孙子定理c语言程序,中国剩余定理(孙子定理)的证明和c++求解

    <孙子算经>里面的"物不知数"说的是这样的一个题目:一堆东西不知道具体数目,3个一数剩2个,5个一数剩3个,7个一数剩2个,问一共有多少个. 书里面给了计算过程及答案: ...

  4. 中国剩余定理 (孙子定理) 的证明和代码

    目录 [引入] [中国剩余定理] [代码实现] [借鉴于] [引入] <孙子算经>里有这样一个题目:今有物不知其数,三三数之剩二,五五数之剩三,七七数之剩二.问物几何? 术曰:" ...

  5. 中国剩余定理——孙子定理

    孙子定理是中国古代求解一次同余式组(见同余)的方法.是数论中一个重要定理.又称中国余数定理. 有物不知其数,三三数之剩二,五五数之剩三,七七数之剩二.问物几何?即,一个整数除以三余二,除以五余三,除以 ...

  6. 中国剩余定理(孙子定理)详解

    为什么发现了这个定理,这要源于一道题 淮安民间传说着一则故事--"韩信点兵",其次有成语"韩信点兵,多多益善".韩信带1500名兵士打仗,战死四五百人,站3人一 ...

  7. BZOJ-1951 古代猪文 (组合数取模Lucas+中国剩余定理+拓展欧几里得+快速幂)...

    数论神题了吧算是 1951: [Sdoi2010]古代猪文 Time Limit: 1 Sec Memory Limit: 64 MB Submit: 1573 Solved: 650 [Submit ...

  8. 中国剩余定理—— 一次同余方程组解法

    文章目录 写在前面 问题的提出 一次同余方程组的计算过程 中国剩余定理 一次同余方程组的求解 例题求解 补充 写在前面 总结一下中国剩余定理,即一次同余方程组的解的存在性分析及计算,为之后的欧拉函数定 ...

  9. 初等数论四大定理(威尔逊定理,欧拉定理,费马小定理,中国剩余定理)

    初等数论四大定理 1. 威尔逊定理 (1) 结论 当且仅当ppp为素数时,(p−1)!≡−1(modp)(p-1)!\equiv -1(\mod p)(p−1)!≡−1(modp). (2) 证明 充 ...

最新文章

  1. 【线下首场免费报名啦】阿里云2020云内存数据库峰会 年度开发者的盛宴
  2. Linux的简介与虚拟机的管理
  3. 质量管理系统_晟通集团内训 | 质量管理系统提升实战训练
  4. LG电子成功进行太赫兹频段6G无线信号传输,距离超过100米
  5. Nginx——反向代理多个服务器
  6. 如何将Tomcat注册为系统服务
  7. 查看自己电脑连接过的WiFi密码
  8. VLIW技术与嵌入式系统
  9. Film Stocks for Mac(PS胶片模拟调色插件)
  10. 关于加油站GPS坐标所想到的解决办法
  11. linux drwxr-xr-x. 什么意思
  12. Python基础教程(第三版)读书笔记(8)
  13. 云原生CI/CD:tekton/pipeline之认证篇
  14. quectel模块增加发送功率流程
  15. Thymeleaf框架
  16. python 删除txt文本指定内容
  17. 微信公众号文章已经获授权加入白名单了,为什么系统还是自动替换成原文章?
  18. python迷宫小游戏代码_TensorFlow应用实战-17-Qlearning实现迷宫小游戏
  19. C语言之变量和数据类型
  20. STM8L的EEPROM读写原理及例程

热门文章

  1. Ubuntu 虚拟机无法联网(NAT模式下)- 解决方法
  2. 【AI】人工智能发展时间轴
  3. c语言 整数转换成二进制 模仿c++的 _itoa() 函数
  4. P30 pro成功升级HarmonyOS!!!!
  5. DR的背景、DR的作用以及DR选举规则
  6. 《C语言及程序设计》实践参考——个人所得税计算器switch语句版
  7. Java复习面试知识点
  8. 程序员眼中的中国传统文化-王阳明《传习录》11
  9. 青龙面板JD稳定更新库
  10. 疯狂的高考志愿填报:做1单收10万,服务全靠“机器人”