题目:http://www.51nod.com/Challenge/Problem.html#!#problemId=1362

首先,\( f[i][j] \) 是一个 \( i \) 次多项式;

如果考虑差分,用一个列向量维护 0 次差分到 \( n \) 次差分即可,在第 \( n \) 次上差分数组已经是一个常数;

最后一行再维护一个 0 次差分的前缀和,0 次差分其实就是答案;

为了预处理 0 位置上的各次差分值,一开始先 n^2 求出 \( f[0][0] \) 到 \( f[n][n] \),差分一下得到初始矩阵;

转移就是本层加上下一层的差分值,得到本层的下一个位置,\( n \) 次的差分值不变;

需要注意快速幂时,子函数是不能传超过大约 500*500 的数组的,所以把矩阵开成全局的;

可惜这样是 \( n^{3}logm \),会TLE;

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int const xn=;
int n,m,f[xn][xn],d[xn][xn],P;
int upt(int x){while(x>=P)x-=P; while(x<)x+=P; return x;}
struct N{
int a[xn][xn];
N(){memset(a,,sizeof a);}
void init(){for(int i=;i<=n+;i++)a[i][i]=;}
void clr(){memset(a,,sizeof a);}
N operator * (const N &y) const
{
N ret;
for(int i=;i<=n+;i++)
for(int k=;k<=n+;k++)
for(int j=;j<=n+;j++)
ret.a[i][j]=upt(ret.a[i][j]+(ll)a[i][k]*y.a[k][j]%P);
return ret;
}
}a,g,t;
void print(N a)
{
for(int i=;i<=n+;i++,puts(""))
for(int j=;j<=n+;j++)printf("%d",a.a[i][j]);
}
void pw(int b)//
{
t.init();
for(;b;b>>=,g=g*g)
if(b&)t=t*g;
}
int main()
{
while(scanf("%d%d%d",&n,&m,&P)!=EOF)
{
memset(f,,sizeof f);
memset(d,,sizeof d);
f[][]=;
for(int i=;i<=n;i++)
for(int j=;j<=n;j++)
{
if(i)f[i][j]=upt(f[i][j]+f[i-][j]);
if(j)f[i][j]=upt(f[i][j]+f[i][j-]);
if(i&&j)f[i][j]=upt(f[i][j]+f[i-][j-]);
}
for(int j=;j<=n;j++)d[][j]=f[n][j];
for(int i=;i<=n;i++)
for(int j=;j<=n-i;j++)d[i][j]=upt(d[i-][j+]-d[i-][j]);
a.clr(); g.clr(); t.clr();
for(int i=;i<=n;i++)a.a[i][]=d[i][];
for(int i=;i<n;i++)g.a[i][i]=g.a[i][i+]=;
g.a[n][n]=;
g.a[n+][]=g.a[n+][n+]=;
pw(m);
int sum=;
for(int i=;i<=n+;i++)
sum=upt(sum+(ll)t.a[][i]*a.a[i][]%P),
sum=upt(sum+(ll)t.a[n+][i]*a.a[i][]%P);
printf("%d\n",sum);
}
return ;
}

差分+矩阵快速幂

其实可以考虑组合数:

因为斜着走既向下又向右,不好判断,所以不妨枚举斜着走了几格,假设 \( n<=m \),得到

\( ans = \sum\limits_{j=0}^{m} \sum\limits_{i=0}^{n} C_{i+j}^{i} * C_{j}^{n-i} \)

即 \( ans = \sum\limits_{j=0}^{m} \sum\limits_{i=0}^{n} C_{n}^{i} * C_{i+j}^{n} \),或者其实可以直接写出这个式子;

然后 \( ans = \sum\limits_{i=0}^{n} C_{n}^{i} * \sum\limits_{j=0}^{m} C_{i+j}^{n} \)

\( ans = \sum\limits_{i=0}^{n} C_{n}^{i} * C_{i+m+1}^{n+1} \)

于是求组合数即可;

但模数不是质数,没有逆元;

可以像扩展 Lucas 的做法一样,提取出模数的质因子,剩余的部分就和模数互质,可以用 exgcd 求逆元;

质因子的部分直接把次数加减即可。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int const xn=,xm=;
int n,m,mod,p[xm],cnt,t[xm];
void div(int x)
{
for(int i=;i*i<=x;i++)
{
if(x%i)continue;
p[++cnt]=i;
while(x%i==)x/=i;
}
if(x>)p[++cnt]=x;
}
ll pw(ll a,int b)
{
ll ret=;
for(;b;b>>=,a=(a*a)%mod)if(b&)ret=(ret*a)%mod;
return ret;
}
void exgcd(int a,int b,int &x,int &y)
{
if(!b){x=; y=; return;}
exgcd(b,a%b,y,x);
y-=a/b*x;
}
int inv(int a,int b){int x,y; exgcd(a,b,x,y); return (x%b+b)%b;}//%b
int get(int x,int tp)
{
for(int i=;i<=cnt;i++)
{
if(x%p[i])continue;
int cnt=;
while(x%p[i]==)cnt++,x/=p[i];
t[i]+=cnt*tp;
}
return x;
}
int C(int n,int m)
{
if(n<m)return ;//!!
if(m==)return ;
memset(t,,sizeof t);
int ret=;
for(int i=n-m+;i<=n;i++)
ret=(ll)ret*get(i,)%mod;
for(int i=;i<=m;i++)
ret=(ll)ret*inv(get(i,-),mod)%mod;
for(int i=;i<=cnt;i++)ret=(ll)ret*pw(p[i],t[i])%mod;
return ret;
}
int main()
{
while(scanf("%d%d%d",&n,&m,&mod)==)
{
cnt=; div(mod); int ans=;
for(int i=;i<=n;i++)
ans=(ans+(ll)C(n,i)*C(i+m+,n+))%mod;
printf("%d\n",ans);
}
return ;
}

51Nod 1362 搬箱子 —— 组合数(非质数取模) (差分TLE)的更多相关文章

  1. 51nod 1362 搬箱子——[ 推式子+组合数计算方法 ] [ 拉格朗日插值 ]

    题目:http://www.51nod.com/Challenge/Problem.html#!#problemId=1362 方法一: 设 a 是向下走的步数. b 是向右下走的步数. c 是向下走 ...

  2. 组合数学中的常见定理&组合数的计算&取模

    组合数的性质: C(n,m)=C(n,n-m); C(n,m)=n!/(m!(n-m)!); 组合数的递推公式: C(n,m)=  C(n-1,m-1)+C(n-1,m); 组合数一般数值较大,题目会 ...

  3. 3-为什么很多 对 1e9+7(100000007)取模

    首先有很多题目的答案是很大的,然而出题人的本意也不是让选手写高精度或者Java,所以势必要让答案落在整型的范围内.那么怎么做到这一点呢,对一个很大的质数取模即可(自行思考为什么不是小数).那么如果您学 ...

  4. 组合数取模及Lucas定理

    引入: 组合数C(m,n)表示在m个不同的元素中取出n个元素(不要求有序),产生的方案数.定义式:C(m,n)=m!/(n!*(m-n)!)(并不会使用LaTex QAQ). 根据题目中对组合数的需要 ...

  5. [BZOJ 3129] [Sdoi2013] 方程 【容斥+组合数取模+中国剩余定理】

    题目链接:BZOJ - 3129 题目分析 使用隔板法的思想,如果没有任何限制条件,那么方案数就是 C(m - 1, n - 1). 如果有一个限制条件是 xi >= Ai ,那么我们就可以将 ...

  6. BZOJ_2142_礼物_扩展lucas+组合数取模+CRT

    BZOJ_2142_礼物_扩展lucas+组合数取模 Description 一年一度的圣诞节快要来到了.每年的圣诞节小E都会收到许多礼物,当然他也会送出许多礼物.不同的人物在小E 心目中的重要性不同 ...

  7. 组合数取模&&Lucas定理题集

    题集链接: https://cn.vjudge.net/contest/231988 解题之前请先了解组合数取模和Lucas定理 A : FZU-2020  输出组合数C(n, m) mod p (1 ...

  8. HDU 5698 大组合数取模(逆元)

    瞬间移动 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submis ...

  9. BZOJ 3656: 异或 (组合数取模 CRT)

    http://www.lydsy.com/JudgeOnline/problem.php?id=3656 大意:经过一通推导,问题变成求\[\binom N M \mod P\],其中N,M<= ...

随机推荐

  1. 根据URL发起HTTP请求,我的HTTPHelper。

     完整的demo using System; using System.Collections.Generic; using System.Linq; using System.Text; using ...

  2. 【Selenium + Python】之如何获取最新的报告以及os.path.getmtime与os.path.getctime的区别

    import os def new_file(test_dir): #列举test_dir目录下的所有文件(名),结果以列表形式返回. lists=os.listdir(test_dir) #sort ...

  3. 部署mongodb中需要注意的调参

    部署mongodb的生产服务器,给出如下相关建议: 使用虚拟化环境: 系统配置 1)推荐RAID配置 RAID(Redundant Array of Independent Disk,独立磁盘冗余阵列 ...

  4. onvif 开发之video streamer---onvif实现功能和经验

    目录(?)[-] 一产生onvif源码框架 从wsdl生成C头文件 从头文件生成源码框架 二创建soap运行环境 三RTSP视频对接 实现GetCapabilities命令 实现GetServices ...

  5. Android API Guides---Storage Access Framework

    存储訪问架构 Android 4.4系统(API级别19)推出存储訪问框架(SAF).新加坡武装部队变得很easy,为用户在其全部自己喜欢的文件存储提供商的浏览和打开文档,图像和其它文件.一个标准的, ...

  6. 在嵌入式、海思、ARM中进行统一的音频AAC编码的必要性

    前言 最近来到深圳,跟许多做硬件的小伙伴聊安防.聊互联网.聊技术,受益颇多,其中聊到一点,大家一直都在想,互联网发展如此迅猛,为啥大部分的摄像机还是采用的传统G.726/G.711的音频编码格式呢,如 ...

  7. Spring Boot启动原理解析

    Spring Boot启动原理解析http://www.cnblogs.com/moonandstar08/p/6550758.html 前言 前面几章我们见识了SpringBoot为我们做的自动配置 ...

  8. php函数: set_error_handler

    <?php // $errno, $errstr, $errfile, $errline , 系统自动生成这四个变量的值(如果存在!) function error_catcher($errno ...

  9. Webpack探索【8】--- 模块热替换详解

    本文主要讲模块热替换相关内容.

  10. python cookbook第三版学习笔记七:python解析csv,json,xml文件

    CSV文件读取: Csv文件格式如下:分别有2行三列. 访问代码如下: f=open(r'E:\py_prj\test.csv','rb') f_csv=csv.reader(f) for f in ...