ccf559c
题意:给出一个矩阵棋盘,大小不超过10^5。上面有n个非法点(n<=2000)不可以踩,从左上角开始走到右下角,每次只能向下或者向右移动。问有多少种走法。结果对10^9+7取模。
分析:
组合数学DP
设dp[i]表示从左上角开始不经过非法点走到第i个非法点有多少种方法。
dp[i]=num(s, point[i]) - sigma( dp[j] * num(point[j], point[i]) );
其中,sigma表示加和,s是起始点,j遍历所有在点i左上方的点。num(a,b)表示从a到b有多少种走法(不用避开非法点)。
num可以直接用组合数表示,即c(x+y-2, x -1)。
这道题涉及到了较大的组合数取模问题。求大组合数方法如下:
可以先处理出所有1~n的阶乘,存入数组。factorial[i]表示i的阶乘取模后的结果。
并求出所有的阶乘在该模运算下的逆元,存入数组。inverse[i]表示factorial[i]的逆元。
c(n,m)原本等于( n! / (n-m)! ) / m!,现在用这两个数组可以表示为factorial[n] * inverse[n-m] * inverse[m]。
模板如下:
#define LL long long const int MAX_M = (int)(2e5) + ;
const int MOD = (int)(1e9) + ; LL multi_mod(LL a, LL b, LL c)
{ //返回(a*b) mod c,a,b,c<2^63
a %= c;
b %= c;
LL ret = ;
while (b)
{
if (b & )
ret = (ret + a) % c;
a <<= ;
a %= c;
b >>= ;
}
return ret;
} LL pow_mod(LL x, LL n, LL mod)
{ //返回x^n mod c ,非递归版
x %= mod;
if (n == )
return x;
LL ret = ;
while (n)
{
if (n & )
ret = multi_mod(ret, x, mod);
n >>= ;
x = multi_mod(x, x, mod);
}
return ret;
} long long get_inverse(long long a)
{
return pow_mod(a, MOD - , MOD);
} long long factorial[MAX_M];
long long inverse[MAX_M]; void init_comb(int n)
{
factorial[] = ;
for (int i = ; i <= n; i++)
{
factorial[i] = factorial[i - ] * i;
factorial[i] %= MOD;
}
inverse[n] = get_inverse(factorial[n]);
for (int i = n - ; i >= ; i--)
{
inverse[i] = inverse[i + ] * (i + );
inverse[i] %= MOD;
}
} long long comb(long long a, long long b)
{
long long ret = factorial[a] * inverse[a - b];
ret %= MOD;
ret *= inverse[b];
ret %= MOD;
return ret;
}
求逆元可以使用扩展欧几里德算法,但是比较麻烦。这次我使用了一个更为简单的算法,费马小定理。
即:当p是质数且a和p互质,那么a^(p-1)=1 (mod p)
而逆元的定义是x * y=1 (mod p)则y是x的逆元。令x=a,且a与p互质,则由a^(p-1)=1 (mod p)可得:y=a^(p-2)。
对于求a的逆元这个问题,a<p且p是质数,自然可以利用上面的结论,a的逆元就是a^(p-2)。
求逆元模板如下:
LL multi_mod(LL a, LL b, LL c)
{ //返回(a*b) mod c,a,b,c<2^63
a %= c;
b %= c;
LL ret = ;
while (b)
{
if (b & )
ret = (ret + a) % c;
a <<= ;
a %= c;
b >>= ;
}
return ret;
} LL pow_mod(LL x, LL n, LL mod)
{ //返回x^n mod c ,非递归版
x %= mod;
if (n == )
return x;
LL ret = ;
while (n)
{
if (n & )
ret = multi_mod(ret, x, mod);
n >>= ;
x = multi_mod(x, x, mod);
}
return ret;
} long long get_inverse(long long a)
{
return pow_mod(a, MOD - , MOD);
}
本题代码如下:
#include <cstdio>
#include <algorithm>
using namespace std; #define d(x)
#define LL long long const int MAX_N = ;
const int MAX_M = (int)(2e5) + ;
const int MOD = (int)(1e9) + ; int row_num, col_num;
int n;
pair<int, int> point[MAX_N];
long long dp[MAX_N]; void input()
{
scanf("%d%d%d", &row_num, &col_num, &n);
for (int i = ; i < n; i++)
{
int a, b;
scanf("%d%d", &a, &b);
point[i] = make_pair(a, b);
}
point[n++] = make_pair(row_num, col_num);
point[n++] = make_pair(, );
for (int i = ; i < n; i++)
{
point[i].first--;
point[i].second--;
}
} LL multi_mod(LL a, LL b, LL c)
{ //返回(a*b) mod c,a,b,c<2^63
a %= c;
b %= c;
LL ret = ;
while (b)
{
if (b & )
ret = (ret + a) % c;
a <<= ;
a %= c;
b >>= ;
}
return ret;
} LL pow_mod(LL x, LL n, LL mod)
{ //返回x^n mod c ,非递归版
x %= mod;
if (n == )
return x;
LL ret = ;
while (n)
{
if (n & )
ret = multi_mod(ret, x, mod);
n >>= ;
x = multi_mod(x, x, mod);
}
return ret;
} long long get_inverse(long long a)
{
return pow_mod(a, MOD - , MOD);
} long long factorial[MAX_M];
long long inverse[MAX_M]; void init_comb(int n)
{
factorial[] = ;
for (int i = ; i <= n; i++)
{
factorial[i] = factorial[i - ] * i;
factorial[i] %= MOD;
}
inverse[n] = get_inverse(factorial[n]);
for (int i = n - ; i >= ; i--)
{
inverse[i] = inverse[i + ] * (i + );
inverse[i] %= MOD;
}
} long long comb(long long a, long long b)
{
long long ret = factorial[a] * inverse[a - b];
ret %= MOD;
ret *= inverse[b];
ret %= MOD;
return ret;
} int main()
{
init_comb();
input();
sort(point, point + n);
dp[] = ;
for (int i = ; i < n; i++)
{
dp[i] = comb(point[i].first + point[i].second, point[i].second);
for (int j = ; j < i; j++)
{
if (point[j].first <= point[i].first && point[j].second <= point[i].second)
{
long long a = point[i].first - point[j].first;
a += point[i].second - point[j].second; long long b = point[i].second - point[j].second; dp[i] -= (dp[j] * comb(a, b)) % MOD;
dp[i] += MOD;
dp[i] %= MOD;
}
}
d(printf("dp[%d] = %d\n", i, (int)dp[i]));
}
printf("%d\n", (int)dp[n - ]);
return ;
}
ccf559c的更多相关文章
随机推荐
- zabbix进程构成
了解完zabbix特性之后,本该进入zabbix安装教程,但是我觉得在安装之前我们很有必要了解一下zabbix进程组成结构,默认情况下zabbix包含5个程序:zabbix_agentd.zabbix ...
- NSUserDefaults standardUserDefaults的使用
本地存储数据简单的说有三种方式:数据库.NSUserDefaults和文件. NSUserDefaults用于存储数据量小的数据,例如用户配置.并不是所有的东西都能往里放的,只支持:NSString, ...
- html 动态显示元素文本
jquery easy ui:http://www.runoob.com/jeasyui/jeasyui-dd-shopping.html <html> <head> < ...
- Xcode常用技巧(1)-使用Xcode进行代码分析及GDB调试
1. 使用Xcode分析代码,分析分为静态分析及动态分析 静态分析:(Xcode-Product-Analyze) 检测代码是否有潜在的内存泄露 编译器认为不太合适的代码 运行结果: 若程序有 ...
- 使程序在Linux下后台运行
一.为什么要使程序在后台执行 我们计算的程序都是周期很长的,通常要几个小时甚至一个星期.我们用的环境是用putty远程连接到日本Linux服务器.所以使程序在后台跑有以下三个好处: 1:我们这边是否关 ...
- javascript简单的认识下return语句+2015的总结+2016的展望
好久没更新博客了...自从有了mac之后世界变得简单了...日常么,除了研究代码,看别人的代码,写自己的代码.就那样.... 吐槽点:window配个nodejs的环境花了九头牛两只老虎的力气,mac ...
- 利用Node.js对某智能家居服务器重构
原文摘自我的前端博客,欢迎大家来访问 http://www.hacke2.cn 之前负责过一个智能家居项目的开发,外包重庆一家公司的,我们主要开发服务器监控和集群版管理. 移动端和机顶盒的远程通信是用 ...
- Mongoose简单的连表查询
原文摘自我的前端博客,欢迎大家来访问 http://www.hacke2.cn 像我这篇文章所说的基于Node.js + jade + Mongoose 模仿gokk.tv,当时停止开发是因为我深深的 ...
- 更简洁的 CSS 清理浮动方式
CSS清理浮动有很多种方式,像使用 br 标签自带的 clear 属,使用元素的 overflow,使用空标签来设置 clear:both 等等.但考虑到兼容问题和语义化的问题,一般我们都会使用如下代 ...
- Request 传值 遇到的中文乱码问题
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="xxxx.aspx.cs&quo ...