【BZOJ2142】礼物 组合数+CRT
【BZOJ2142】礼物
Description
Input
Output
若不存在可行方案,则输出“Impossible”,否则输出一个整数,表示模P后的方案数。
Sample Input
4 2
1
2
Sample Output
【样例说明】
下面是对样例1的说明。
以“/”分割,“/”前后分别表示送给第一个人和第二个人的礼物编号。12种方案详情如下:
1/23 1/24 1/34
2/13 2/14 2/34
3/12 3/14 3/24
4/12 4/13 4/23
【数据规模和约定】
设P=p1^c1 * p2^c2 * p3^c3 * … *pt ^ ct,pi为质数。
对于100%的数据,1≤n≤109,1≤m≤5,1≤pi^ci≤10^5。
题解:答案很简单,$ans=C_{tot}^{w1}C_{tot-w1}^{w2}C_{tot-w1-w2}^{w3}...$。
但是问题来了,首先模数既不是质数,也不是若干独立质数的乘积,而是质数的幂次之积。我们还是先用中国剩余定理,将模数变成质数的幂次,但此时普通的lucas定理无法使用,我们怎么求组合数呢?
我们考虑将组合数变成阶乘相除的形式,再将分子和分母中的阶乘都化成$a\times p^b$的形式(a对$p^c$取模),最后答案的a等于分子的a乘上分母的a的逆元,答案的b等于分子的b-分母的b。那么我们考虑如何将一个数的阶乘化成$a\times p^b$的形式。
以$p=5,p^c=25$为例,然后将n的阶乘中5的倍数都提出来考虑:
$n!=(1\times2\times3\times4\times6\times7\times...)\times5^{\lfloor\frac n 5\rfloor}\times(\lfloor\frac n 5\rfloor)!$
那么如何处理前面的那坨东西呢?我们可以先预处理出$1...24$的阶乘(不计算p的倍数),即为jc,然后前面的那堆东西就变成了$jc[24]^{\lfloor \frac n {25}\rfloor}\times jc[n\%25]$。
对于后面的那个阶乘,我们可以递归处理下去,每次n的大小会除以p,所以复杂度是可以接受的~
最后用CRT合并,求逆元时用exgcd即可,注意判Impossible的情况。
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
typedef long long ll;
const int maxn=100010;
ll n,m,num,P,PP,PC,Pri,ans;
ll w[10],jc[maxn];
inline ll pm(ll x,ll y)
{
ll ret=1;
while(y)
{
if(y&1) ret=ret*x%PP;
x=x*x%PP,y>>=1;
}
return ret;
}
void exgcd(ll a,ll b,ll &x,ll &y)
{
if(!b)
{
x=1,y=0;
return ;
}
exgcd(b,a%b,x,y);
ll t=x;
x=y,y=t-a/b*x;
}
inline ll ine(ll a)
{
ll x,y;
exgcd(a,PP,x,y);
return x;
}
struct node
{
ll x,y;
node() {x=1,y=0;}
node(ll a,ll b) {x=a,y=b;}
node operator + (const node &a) const {return node(x*a.x%PP,y+a.y);}
node operator * (const ll &a) const {return node(pm(x,a),y*a);}
node operator - (const node &a) const {return node(x*(ine(a.x)+PP)%PP,y-a.y);}
};
inline node getjc(ll x)
{
if(x<P) return node(jc[x],0);
return node(pm(jc[PP-1],x/PP)*jc[x%PP]%PP,x/P)+getjc(x/P);
}
inline ll solve()
{
ll i,sum=n;
for(jc[0]=1,i=1;i<PP;i++)
{
jc[i]=jc[i-1];
if(i%P) jc[i]=jc[i]*i%PP;
}
node a,b;
for(i=1;i<=m;i++) b=b+getjc(w[i]),sum-=w[i];
a=getjc(n),b=b+getjc(sum);
a=a-b;
return a.x*pm(P,a.y);
}
inline ll CRT()
{
ll i,t=Pri;
for(i=2;i*i<=t;i++)
{
if(t%i==0)
{
P=i,PP=1,PC=0;
while(t%i==0) t/=i,PP*=i,PC++;
ans=(ans+ine(Pri/PP)*solve()*(Pri/PP))%Pri;
}
}
if(t!=1)
{
P=PP=t,PC=1;
ans=(ans+ine(Pri/PP)*solve()*(Pri/PP))%Pri;
}
return (ans+Pri)%Pri;
}
int main()
{
scanf("%lld%lld%lld",&Pri,&n,&m);
ll tmp=0;
for(ll i=1;i<=m;i++) scanf("%lld",&w[i]),tmp+=w[i];
if(tmp>n)
{
printf("Impossible");
return 0;
}
printf("%lld",CRT());
return 0;
}
【BZOJ2142】礼物 组合数+CRT的更多相关文章
- BZOJ 2142 礼物 组合数学 CRT 中国剩余定理
2142: 礼物 Time Limit: 10 Sec Memory Limit: 259 MBSubmit: 1450 Solved: 593[Submit][Status][Discuss] ...
- [BZOJ2142]礼物(扩展Lucas)
2142: 礼物 Time Limit: 10 Sec Memory Limit: 259 MBSubmit: 2286 Solved: 1009[Submit][Status][Discuss] ...
- [bzoj2142]礼物(扩展lucas定理+中国剩余定理)
题意:n件礼物,送给m个人,每人的礼物数确定,求方案数. 解题关键:由于模数不是质数,所以由唯一分解定理, $\bmod = p_1^{{k_1}}p_2^{{k_2}}......p_s^{{k_ ...
- BZOJ2142: 礼物(拓展lucas)
Description 一年一度的圣诞节快要来到了.每年的圣诞节小E都会收到许多礼物,当然他也会送出许多礼物.不同的人物在小E 心目中的重要性不同,在小E心中分量越重的人,收到的礼物会越多.小E从商店 ...
- BZOJ2142礼物——扩展卢卡斯
题目描述 一年一度的圣诞节快要来到了.每年的圣诞节小E都会收到许多礼物,当然他也会送出许多礼物.不同的人物在小E 心目中的重要性不同,在小E心中分量越重的人,收到的礼物会越多.小E从商店中购买了n件礼 ...
- BZOJ2142 礼物 扩展lucas 快速幂 数论
原文链接http://www.cnblogs.com/zhouzhendong/p/8110015.html 题目传送门 - BZOJ2142 题意概括 小E购买了n件礼物,送给m个人,送给第i个人礼 ...
- bzoj2142 礼物——扩展卢卡斯定理
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2142 前几天学了扩展卢卡斯定理,今天来磕模板! 这道题式子挺好推的(连我都自己推出来了) , ...
- HZOI20190722 B visit 组合数+CRT合并
题目:https://www.cnblogs.com/Juve/articles/11226266.html solution: 30%:dp 设dp[k][i][j]表示经过k时间,在(i,j)的方 ...
- bzoj2142: 礼物
2142: 礼物 Description 一年一度的圣诞节快要来到了.每年的圣诞节小E都会收到许多礼物,当然他也会送出许多礼物.不同的人物在小E心目中的重要性不同,在小E心中分量越重的人,收到的礼物会 ...
随机推荐
- IOS多线程之Block编程
1 什么是block iOS SDK 4.0開始,Apple引入了block这一特性.字面上说,block就是一个代码块.可是它的奇妙之处在于在内联(inline)运行的时候(这和C++非常像)还 ...
- 为什么要把session存入数据库
比如网易的通行证,一个session能进入很多的网易下的网站
- 关于Unity中UI中的Mask组件、Text组件和布局
一.Mask组件 遮罩,Rect Mask矩形Mask(Rect Mask2D组件),图片Mask(Mask组件)(图片Mask的透明度不为0的部分显示子图片,为0的部分不显示子图片) Rect Ma ...
- 在caffe中增加和convolution相同的层
1.打开vision_layers.hpp,复制ConvolutionLayer的代码,把类名还有构造函数的名字改为WtfLayer,把里面的带GPU的函数删掉. 2.Wtf_layer.cpp 添加 ...
- python + opencv: 解决不能读取视频的问题
博主一开始使用python2.7和Opencv2.4.10来获取摄像头图像,程序如下: cap = cv2.VideoCapture(0) ret, frame = cap.read() 使用这个程序 ...
- C++ 判断目录是否存在并新建目录
http://blog.csdn.net/u012005313/article/details/50688257 #include <io.h> #include <string&g ...
- 【转】MFC CListCtrl 使用技巧
以下未经说明,listctrl默认view 风格为report 相关类及处理函数 MFC:CListCtrl类 SDK:以 “ListView_”开头的一些宏.如 ListView_InsertCol ...
- FFmpeg在Android上的移植优化步骤
http://blog.csdn.net/feixiang_john/article/details/7894188 从事多媒体软件开发的人几乎没有不知道FFmpeg的,很多视频播放器都是基于FFmp ...
- yasm开源汇编器分析
https://www.google.com.hk/search?q=yasm&oq=yasm&aqs=chrome..69i57&sourceid=chrome&es ...
- 双卡手机怎么指定SIM卡打电话
双卡手机如何指定SIM卡打电话 package com.example.dualsimtest; import android.app.Activity; import android.content ...