【spoj SEQN】【hdu 3439】Sequence
题意:
给出n、m、k 求C(n,k)*H(n-k)%m的值 H(n-k)为错排公式
题解:
先算H(n-k)
计算H(n)有个通式:
H(n)=(-1)^n+((-1)^(n-1))n+((-1)^(n-2))n(n-1)+...+n(n-1)(n-2)...3
证明详见维基百科:
因为我们是要算H(n-k)mod m的值 显然他的前不超过m项是>0的 而其它都为0 枚举求解即可
_________________________________________________________________________________
再说C(n,k)%m
我们知道世界上有个叫 Lucas 定理的东西:
C(n, m) % p = C(n / p, m / p) * C(n % p, m % p) % p
但是它要求p是质数 所以它和本题的正解没什么关系- -
_________________________________________________________________________________
由于除的数可能不与m互质 所以不能用乘法逆元
不妨将m分解 m=p1^a1*p2^a2*...*pn^an
分别计算C(n,k)%(pi^ai) 的值 最后用中国剩余定理计算答案
于是问题转换为求C(n,k)%(p^a)的值
C(n,k)=n!/((n-k)!*k!)
为了让乘法逆元能能使用 只要将n!、(n-k)!、k! 所有p的倍数 提出来单独计算即可
如果n比较小 枚举计算不为p的倍数的数的积即可 但是这里n<=10^9 我们就需要用一些比较高端的方法
设A(n)=(1*2*..*(p-1)*(p+1)*...*(2p-1)*(2p+1)*...*n)
n!=A(n)*(p*2p*...*(n/p)p)
=A(n)*(n/p)!*p^(n/p)
=A(n)*A(n/p)*(n/p/p)!*p^(n/p/p)*p^(n/p)
=...
就是对n!不断的分解为A(n)*(n/p)!*p^(n/p) 再递归处理(n/p)! 直到n/p为0
当然在计算的同时 要累加/减 p的指数sum
这样就能求出C(n,k)不包含p的乘积了 最后再乘p^sum 即为C(n,k)%(p^a)
_________________________________________________________________________________
问题结束了吗- - 显然木有 对于A(n)还需要用O(n)的时间求出 TLE!
设r=p^a
这里A(n)的值是要模r的 我们可以这样转换
A(n)=1*2*..*(p-1)*(p+1)*...*(2p-1)*(2p+1)*...*n
=(1*2*...*(r-1))*((r+1)*(r+2)*...*(2r-1))*(...*n)
=(1*2*...*(r-1))*(1*2*...*(r-1))*...*(1*2*...*n%r) (mod r)
我们就可以预处理save[i]存下1*2*...*i (p的倍数不乘,i<=r-1)
A(n)=save[r-1]^(n/r)*save[n%r] 快速幂就可用log(n)的时间求出A
加上预处理O(r) r<=m<=10^5
最后乘m的质因数的个数blabla- -具体多少我也不知道了 反正能过
_________________________________________________________________________________
代码:
#include <cstdio>
typedef long long ll;
const ll M=;
ll n,k,m,t,a[M],r[M],ans,p[M],pri[M],bo[M],zs[M],save[M],tot;
void makepri(){
for (ll i=;i<M;i++){
if (!bo[i]) pri[++pri[]]=i;
for (ll j=;j<=pri[] && i*pri[j]<M;j++){
bo[i*pri[j]]=;
if (!(i%pri[j])) break;
}
}
}
ll mi(ll a,ll b,ll mo){
ll res=%mo;
for (;b;b>>=){
if (b&) res=res*a%mo;
a=a*a%mo;
}
return res;
}
ll extgcd(ll &x,ll &y,ll a,ll b){
if (!b){
x=,y=;
return a;
}else{
ll res=extgcd(x,y,b,a%b);
ll t=x;
x=y;
y=t-a/b*y;
return res;
}
}
ll getny(ll a,ll b){
ll x,y,gc=extgcd(x,y,a,b),mo=b/gc;
x=(x%mo+mo)%mo;
return x;
} void makep(){
p[]=r[]=;
for (ll i=,x=m;i<=pri[] && x>;i++)
if (!(x%pri[i])){
p[++p[]]=pri[i];
r[++r[]]=;
while (!(x%pri[i])) x/=pri[i],r[r[]]*=pri[i];
}
}
void makesave(ll t){
save[]=;
for (ll i=,x=;i<=r[t];i++){
if (i%p[t]) x=x*i%r[t];
save[i]=x;
}
}
ll jc(ll n,ll t,ll &z,ll bo){
if (!n) return ;
z+=bo*(n/p[t]);
return mi(save[r[t]],n/r[t],r[t])*save[n%r[t]]%r[t]*jc(n/p[t],t,z,bo)%r[t];
}
ll getc(){
makep();
for (ll i=;i<=p[];i++){
zs[i]=;
makesave(i);
a[i]=jc(n,i,zs[i],)*getny(jc(n-k,i,zs[i],-)*jc(k,i,zs[i],-)%r[i],r[i])%r[i];
a[i]=a[i]*mi(p[i],zs[i],r[i])%r[i];
}
ll res=;
for (ll i=;i<=p[];i++)
res=(res+m/r[i]*getny(m/r[i],r[i])%m*a[i]%m)%m;
return res;
} ll geth(ll n){
if (n==) return ;
ll res=(n&) ? - : ;
for (ll i=n,x=n*res*-%m;i>= && x;x=x*(--i)*-%m)
res=((res+x)%m+m)%m;
return res;
} int main(){
scanf("%I64d",&t);
makepri();
for (ll i=;i<=t;i++){
tot=i;
scanf("%I64d%I64d%I64d",&n,&k,&m);
ans=(getc()*geth(n-k)%m+m)%m;
printf("Case %I64d: %I64d\n",i,ans);
}
}
注:这个代码能过hdu的数据但是不能过spoj的... 可能有点小bug- -?(我说spoj → →)
【spoj SEQN】【hdu 3439】Sequence的更多相关文章
- 【改革春风吹满地 HDU - 2036 】【计算几何-----利用叉积计算多边形的面积】
利用叉积计算多边形的面积 我们都知道计算三角形的面积时可以用两个邻边对应向量积(叉积)的绝对值的一半表示,那么同样,对于多边形,我们可以以多边形上的一个点为源点,作过该点并且过多边形其他点中的某一个的 ...
- 【 SPOJ - GRASSPLA】 Grass Planting (树链剖分+树状数组)
54 种草约翰有 N 个牧场,编号为 1 到 N.它们之间有 N − 1 条道路,每条道路连接两个牧场.通过这些道路,所有牧场都是连通的.刚开始的时候,所有道路都是光秃秃的,没有青草.约翰会在一些道 ...
- 【HDU 2255】奔小康赚大钱 (最佳二分匹配KM算法)
奔小康赚大钱 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Subm ...
- 【二分】【最长上升子序列】HDU 5489 Removed Interval (2015 ACM/ICPC Asia Regional Hefei Online)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5489 题目大意: 一个N(N<=100000)个数的序列,要从中去掉相邻的L个数(去掉整个区间 ...
- 【贪心】【模拟】HDU 5491 The Next (2015 ACM/ICPC Asia Regional Hefei Online)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5491 题目大意: 一个数D(0<=D<231),求比D大的第一个满足:二进制下1个个数在 ...
- 【动态规划】【二分】【最长上升子序列】HDU 5773 The All-purpose Zero
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5773 题目大意: T组数据,n个数(n<=100000),求最长上升子序列长度(0可以替代任何 ...
- 【动态规划】【KMP】HDU 5763 Another Meaning
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5763 题目大意: T组数据,给两个字符串s1,s2(len<=100000),s2可以被解读成 ...
- 【归并排序】【逆序数】HDU 5775 Bubble Sort
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5775 题目大意: 冒泡排序的规则如下,一开始给定1~n的一个排列,求每个数字在排序过程中出现的最远端 ...
- 【中国剩余定理】【容斥原理】【快速乘法】【数论】HDU 5768 Lucky7
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5768 题目大意: T组数据,求L~R中满足:1.是7的倍数,2.对n个素数有 %pi!=ai 的数 ...
随机推荐
- PJSIP在windows(xp或者win7)下的编译,编译工具是vs2008,PJSIP版本2.3
PJSIP是一个开源的SIP协议库,它实现了SIP.SDP.RTP.STUN.TURN和ICE.PJSIP作为基于SIP的一个多媒体通信框架提供了非常清晰的API,以及NAT穿越的功能.PJSIP具有 ...
- 97. Interleaving String
题目: Given s1, s2, s3, find whether s3 is formed by the interleaving of s1 and s2. For example,Given: ...
- P94、面试题12:打印1到最大的n位数
题目:输入数字n,按顺序打印出从1最大的n位十进制数.比如输入3,则打印出1,2,3一直到最大的3位数999. 思路:先把字符串中的每一个数字都初始化为‘0’,然后每一次为字符串表示的数字加1,再打印 ...
- 【HDOJ】3007 Buried memory
1. 题目描述有n个点,求能覆盖这n个点的半径最小的圆的圆心及半径. 2. 基本思路算法模板http://soft.cs.tsinghua.edu.cn/blog/?q=node/1066定义Di表示 ...
- grunt安装中的cli和--save-dev解释
grunt官网安装grunt的介绍中是这么写的: npm install -g grunt-cli 这里安装Grunt的命令行支持(command line interface,简称CLI),在这之后 ...
- JAX-RS入门 二 :运行
上一节,已经成功的定义了一个REST服务,并且提供了具体的实现,不过我们还需要把它运行起来. 在上一节的装备部分,列举了必须的jar(在tomcat中运行)和可选的jar(作为一个独立的应用程序运行) ...
- Oracle查看LogMiner的详解
Oracle数据库查看日志的方法很多,我们可以根据SQL语句来实现,也可以通过日志查看工具LogMiner来实现,本文我们主要就介绍了这一过程,接下来就让我们一起来了解一下吧. 一.Or ...
- linux 下使用 cmake安装mysql
原文地址:http://www.cppblog.com/issay789/archive/2013/01/05/196967.html 一.安装 m4 下载地址: http://files.w3pc. ...
- cell1这个字符串如何截取掉前边的cell剩下后边的数字 后边数字长度不固定
cell1这个字符串如何截取掉前边的cell剩下后边的数字 后边数字长度不固定'cell1'.replace(/cell/,'')string.substr(4)string.slice(4)
- CF GYM 100703I Endeavor for perfection
题意:有n个学习领域,每个领域有m个课程,学习第i个领域的第j个课程可以获得sij个技能点,在每个领域中选择一个课程,要求获得的n个技能点的最大值减最小值最小,输出符合要求的策略. 解法:尺取法.将课 ...