hdu5526
来源:互联网 发布:淘宝男装潮店 编辑:程序博客网 时间:2024/06/05 01:54
小明和他的矩阵
题目描述:
Tom放学回家的路上,看到天空中出现一个矩阵。Tom发现,如果矩阵的行、列从0开始标号,第i行第j列的数记为ai,j,那么ai,j=Cji
如果i < j,那么ai,j=0
Tom突发奇想,想求一个矩形范围内所有数的和。Tom急着回家,当然不会自己算,所以就把任务交给你了。
因为数可能很大,答案对一个质数p取模
输入:输入包含多组数据(大约8组)。每组数据只有一行五个非负整数,x1、y1、x2、y2、p,你要求的是∑x2i=x1∑y2j=y1ai,j模p后的值。
x1≤x2≤1e5,y1≤y2≤1e5,2≤p≤1e9
题解:
发现一列一列的看最好,利用【l,r】区间的方法,算出【0,r】的就好,发现每一列是上标相同的组合数,那么之前加一项,之后再减去就能变成一个组合数。然后每一列算一次累加起来就好了。剩下关键是怎么求组合数并且MODp。本来是用欧拉定理算逆元推,但是要求x和p互质,p是质数,但是如果p太小,比如p是2,x是4,就跪了。于是隆重推出专门算组合数的lucas定理:C【n】[m] = C[n/p][m/p]*C[n%p][m%p]%p;
这样一来,对于C[n%p][m%p]来说,都小于p,预处理出来阶层,可以用逆元直接搞,C[n/p][m/p]是一直递归下去,logn就搞定。
重点:
首先,发现每一列的规律,这是这道题的关键思路。其次,认识到当MOD太小的时候,组合数要用预处理阶层+Lucas定理
代码:
#include <iostream>#include <cstdio>#include <cstring>#include <string>#include <cmath>#include <ctype.h>#include <limits.h>#include <cstdlib>#include <algorithm>#include <vector>#include <queue>#include <map>#include <stack>#include <set>#include <bitset>#define CLR(a) memset(a, 0, sizeof(a))#define REP(i, a, b) for(ll i = a;i < b;i++)#define REP_D(i, a, b) for(ll i = a;i <= b;i++)typedef long long ll;using namespace std;const ll maxn = 1e5 + 100;ll jiecheng[maxn];ll x_1, x_2, y_2, y_1;ll p;void getJiecheng()//预处理阶层{ jiecheng[0] = 1; REP_D(i, 1, 100000) { jiecheng[i] = jiecheng[i-1]*i%p; }}ll pow_mod(ll x, ll n, ll M)//求逆元{ if(n==0) return 1; ll xx = x*x%(M); ll nn = n/2; ll ans = pow_mod(xx, nn, M); if(n%2==1) { ans = (ans*x)%(M); } return ans;}ll getC(ll n, ll m)//递归版lucas定理求C{ if(m > n)//特判 return 0; if(m == 0||n == m)//小边界 return 1; ll a = n%p, b = m%p; if(a < b)//特判 return 0; else return getC(n/p, m/p)*jiecheng[a]%p*pow_mod(jiecheng[b], p-2, p)%p*pow_mod(jiecheng[a-b], p-2, p);}ll gao(ll a, ll b, ll x)//算从列a到列b然后x已经加过一了。具体公式自己推一下就好{ if(a + 1 > x) return 0; ll ans = 0; //ll tmp = 1;// REP_D(i, 1, a)// {// tmp = (tmp*(x-i+1)%p*pow_mod(i, p-2, p)%p);// } REP_D(i, a + 1, b + 1) { if(i > x) break; //tmp = (tmp*(x-i+1)%p*pow_mod(i, p-2, p)%p); ans = (ans + getC(x, i))%p; } return ans;}void solve(){ ll ans = 0; ans = gao(y_1, y_2, x_2 + 1);//【l,r】方法 if(x_1 != 0) ans = ((ans - gao(y_1, y_2, x_1))%p + p)%p; printf("%I64d\n", ans);}int main(){ freopen("3Cin.txt", "r", stdin); //freopen("3Cout.txt", "w", stdout); while(scanf("%I64d%I64d%I64d%I64d%I64d", &x_1, &y_1, &x_2, &y_2, &p) != EOF) { getJiecheng(); solve(); } return 0;}
0 0
- hdu5526
- hdu5526 贪心
- 二进制中1的个数
- SSH连接CentOS中文显示乱码
- 常用颜色的RGB分布
- c++const成员函数与mutable关键词
- 配置session存储到memcached
- hdu5526
- java Slipped Conditions
- Phoenix(十)二级索引之— —Append-only Data
- WordPress程序代码块高亮显示插件wp-syntax使用
- 深度学习方法(五):卷积神经网络CNN经典模型整理Lenet,Alexnet,Googlenet,VGG,Deep Residual Learning
- CI等框架项目出现白屏(PHP5.5)
- 最近涉及reflector中反编代码修改,在此积累经验
- 接口声明-抽象类空实现-继承重写来实现适配器的模式
- openssl-1.0.1e for arm