【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开发中的错误整理,导航控制器的导航栏取消系统渲染的错误
- java判断邮件是否发送成功
http://www.cnblogs.com/winner-0715/p/5136392.html
- 实现整数转化为字符串函数itoa()函数
函数原型: char *itoa( int value, char *string,int radix);原型说明:value:欲转换的数据.string:目标字符串的地址.radix:转换后的进制数 ...
- 符号arg含义
argument of the maximum/minimum arg max f(x): 当f(x)取最大值时,x的取值 arg min f(x):当f(x)取最小值时,x的取值 表示使目标函数取最 ...
- Linux 精确获取指定目录对应的块的剩余空间
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/statfs ...
- 修改MySQL的默认密码的四种小方法
投稿:lijiao 字体:[增加 减小] 类型:转载 时间:2015-09-05我要评论 对于windows平台来说安装完MySQL后,系统就已经默认生成了许可表和账户,下文中就教给大家如何修改MyS ...
- (转)如何根据RGB值来判断这是种什么颜色?
如何根据RGB值来判断这是种什么颜色? 下面介绍几种典型颜色的RGB值,格式为:颜色(R,G,B). 想象一下有红.绿.蓝三盏射灯打出三束光. 这三束光叠加在一起时产生白色,如果三盏灯的亮度都减半就产 ...
- SVN版本冲突,导致出现Files 的值“ < < < < < < < .mine”无效。路径中具有非法字符。
SVN版本冲突,导致出现Files 的值“ < < < < < < < .mine”无效.路径中具有非法字符. 右键编辑.... 打开并删除含有'<&l ...
- mysql压缩包的安装、配置、配成windows服务、远程连接及常规问题
1.下载windows安装包 下载地址:mysql-5.7.18 2.配置my.ini [client] port = 3306 # 设置mysql客户端连接服务端时默认使用的端口 [mysql] d ...
- PHP实现金额数字转换成大写函数
<?php header("Content-Type:text/html;charset=utf-8"); function num_to_upper($num) { $d ...