51Nod 1362 搬箱子 —— 组合数(非质数取模) (差分TLE)
题目: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)的更多相关文章
- 51nod 1362 搬箱子——[ 推式子+组合数计算方法 ] [ 拉格朗日插值 ]
题目:http://www.51nod.com/Challenge/Problem.html#!#problemId=1362 方法一: 设 a 是向下走的步数. b 是向右下走的步数. c 是向下走 ...
- 组合数学中的常见定理&组合数的计算&取模
组合数的性质: 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-为什么很多 对 1e9+7(100000007)取模
首先有很多题目的答案是很大的,然而出题人的本意也不是让选手写高精度或者Java,所以势必要让答案落在整型的范围内.那么怎么做到这一点呢,对一个很大的质数取模即可(自行思考为什么不是小数).那么如果您学 ...
- 组合数取模及Lucas定理
引入: 组合数C(m,n)表示在m个不同的元素中取出n个元素(不要求有序),产生的方案数.定义式:C(m,n)=m!/(n!*(m-n)!)(并不会使用LaTex QAQ). 根据题目中对组合数的需要 ...
- [BZOJ 3129] [Sdoi2013] 方程 【容斥+组合数取模+中国剩余定理】
题目链接:BZOJ - 3129 题目分析 使用隔板法的思想,如果没有任何限制条件,那么方案数就是 C(m - 1, n - 1). 如果有一个限制条件是 xi >= Ai ,那么我们就可以将 ...
- BZOJ_2142_礼物_扩展lucas+组合数取模+CRT
BZOJ_2142_礼物_扩展lucas+组合数取模 Description 一年一度的圣诞节快要来到了.每年的圣诞节小E都会收到许多礼物,当然他也会送出许多礼物.不同的人物在小E 心目中的重要性不同 ...
- 组合数取模&&Lucas定理题集
题集链接: https://cn.vjudge.net/contest/231988 解题之前请先了解组合数取模和Lucas定理 A : FZU-2020 输出组合数C(n, m) mod p (1 ...
- HDU 5698 大组合数取模(逆元)
瞬间移动 Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submis ...
- BZOJ 3656: 异或 (组合数取模 CRT)
http://www.lydsy.com/JudgeOnline/problem.php?id=3656 大意:经过一通推导,问题变成求\[\binom N M \mod P\],其中N,M<= ...
随机推荐
- 这样好用的ReactiveCocoa,根本停不下来【转载】
前戏我个人非常推崇ReactiveCocoa,它就像中国的太极,太极生两仪,两仪生四象,四象生八卦,八卦生万物.ReactiveCocoa是一个高度抽象的编程框架,它真的很抽象,初看你不知道它是要干嘛 ...
- win7查看端口占用
1.查看谁占用了我们的80端口,在windows命令行窗口下执行: netstat -aon|findstr 80 发现80端口被进程号为2596的进程占用.2.查看占用80端口进程的应用程序是什 ...
- ASP.NET动态网站制作(13)-- JQ(5)
前言:jq的最后一节课,主要讲解应用, 内容: 1.会飞的li: HTML代码: <!DOCTYPE html> <html xmlns="http://www.w3.or ...
- 配置springMVC时出现的问题
配置springMVC时出现的问题 项目结构如图:
- 经常遇到js的面试题
大家都知道在面试的时候,很多前端的必须要问的就是js的问题,最近我们公司也有很多这样的面试,我提了一些个问题,还有我面试的时候面试官面试我的问题汇总,也有百度的别人的,希望对那些刚进入这个行业的有一些 ...
- 远程服务器上的weblogic项目管理(一)项目部署与更新流程
最近接手了项目组的服务器管理工作,服务器以linux系统为主,项目则搭建在weblogic上面,也算是积累了一些远程管理服务器的心得,决定稍微整理一下: windows系统要如何方便地连接到远程服务器 ...
- Tomcat学习笔记【5】--- 项目部署详解
本文主要讲在Tomcat中部署项目的几种方式:静态部署.动态部署. 一 静态部署 静态部署项目有好几种方式,比较典型的有如下4种: 1.1 方式一:将Web项目放到webApps目录下 直接将web项 ...
- display:inline
一.基本介绍 它可以让行内显示为块的元素,变为行内显示,例如 <div> DIV1 </div> <div> DIV2 </div> 这里DIV1和DI ...
- Algorithm: bit manipulation
1. 一个数的从右起第p1位和第p2位swap n位 unsigned int swapBits(unsigned int x, unsigned int p1, unsigned int p2, u ...
- Android Weekly Notes Issue #290
Android Weekly Issue #290 December 31st, 2017 Android Weekly Issue #290 本期内容包括介绍Kotlin逆变协变的一篇(虽然没说清楚 ...