BZOJ 2142 礼物 组合数学 CRT 中国剩余定理
2142: 礼物
Time Limit: 10 Sec  Memory Limit: 259 MB
Submit: 1450  Solved: 593
[Submit][Status][Discuss]
Description
一年一度的圣诞节快要来到了。每年的圣诞节小E都会收到许多礼物,当然他也会送出许多礼物。不同的人物在小E心目中的重要性不同,在小E心中分量越重的人,收到的礼物会越多。小E从商店中购买了n件礼物,打算送给m个人,其中送给第i个人礼物数量为wi。请你帮忙计算出送礼物的方案数(两个方案被认为是不同的,当且仅当存在某个人在这两种方案中收到的礼物不同)。由于方案数可能会很大,你只需要输出模P后的结果。
Input
输入的第一行包含一个正整数P,表示模;第二行包含两个整整数n和m,分别表示小E从商店购买的礼物数和接受礼物的人数;以下m行每行仅包含一个正整数wi,表示小E要送给第i个人的礼物数量。
Output
若不存在可行方案,则输出“Impossible”,否则输出一个整数,表示模P后的方案数。
Sample Input
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。
HINT
Source
Solution
根据题目大意可以列出式子C(n,sum)*C(sum, w[1])*C(sum-w[1], w[2])··········
如果p是质数的话,显然就是Lucas的裸题。
但现在p不是质数了,要怎么办呢?把p分解成一个个pi^ci,这样的话就保证了两两互质,CRT求解。
那怎么算C(x,y)%(pi^ci)呢?把C(x,y)转化成x!、y!和(x-y)!。
由于需要求逆元,而n!不一定与pi^ci互质,我们就需要把n!分解为k*(pi^x),其中,k与pi互质。
对于当前的n!,我们发现可以把它整理为一些模(pi^ci)下的循环串乘上(pi^(n/pi))再乘上(n/pi)!
举个栗子,17!%(3^2) = (1*2*4*5*7*8*10*11*13*14*16*17)*(3^5)*(1*2*3*4*5)
很显然,栗子最后的那部分就是5!%3这个显然可以递归下去。
对于最前的那部分,我们可以发现,它是由一些循环节(模3^2下)组成的,且均不含有质因数3。
仔细分析,就是[1,3^2]中与质因数3互质的数。求出循环节之后就可以直接用快速幂完成。
对于中间的部分,我们收集起来,算组合数的时候统一再做一次快速幂。
本题主要的问题是处理好逆元的问题,把n!分解成k*(pi^x),含pi的部分单独算,k与pi^ci互质,可以直接求解逆元。
Code
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm> using namespace std; #define REP(i, a, b) for (int i = (a), i##_end_ = (b); i <= i##_end_; ++i)
#define fi first
#define se second
#define mp make_pair
typedef long long LL;
typedef pair<LL, LL> pa;
const int maxn = 1e5;
LL p, a[];
LL prime[maxn+], p_cnt;
bool isNotPrime[maxn+];
LL p_num[], p_mod[], p_sum[], cnt; void prepare()
{
REP(i, , maxn)
{
if (!isNotPrime[i]) prime[++p_cnt] = i;
REP(j, , p_cnt)
{
if (i*prime[j] > maxn) break ;
isNotPrime[i*prime[j]] = ;
if (i%prime[j] == ) break ;
}
}
LL temp = p;
REP(i, , p_cnt)
{
if (prime[i] > temp || temp == ) break ;
if (temp%prime[i] == )
{
p_num[++cnt] = prime[i], p_mod[cnt] = , p_sum[cnt] = ;
while (temp%prime[i] == )
p_mod[cnt] *= prime[i], p_sum[cnt] ++, temp /= prime[i];
}
}
} LL power(LL x, LL y, LL MOD)
{
LL ret = ;
while (y > )
{
if (y&) ret = (ret*x)%MOD;
x = (x*x)%MOD;
y >>= ;
}
return ret;
} pa calc(int k, LL num)
{
if (num == ) return mp(, );
LL x = num/p_num[k], y = num/p_mod[k];
LL ans = ;
if (y)
{
LL t_num = ;
REP(i, , p_mod[k]-)
if (i%p_num[k] != ) t_num = (t_num*i)%p_mod[k];
ans = power(t_num, y, p_mod[k]);
}
if (num%p_mod[k] != )
{
REP(i, , num%p_mod[k])
if (i%p_num[k] != ) ans = (ans*i)%p_mod[k];
}
pa temp = calc(k, x);
return mp(temp.fi+x, temp.se*ans%p_mod[k]);
} LL ex_gcd(LL aa, LL bb, LL &x, LL &y)
{
if (bb == )
{
x = , y = ;
return aa;
}
LL ret = ex_gcd(bb, aa%bb, x, y);
LL temp = x;
x = y, y = temp-(aa/bb)*y;
return ret;
} LL inv(LL k, LL MOD)
{
LL x, y;
ex_gcd(k, MOD, x, y);
x = (x%MOD+MOD)%MOD;
return x;
} LL CRT()
{
LL ret = ;
REP(i, , cnt)
{
LL Mi = p/p_mod[i];
ret = (ret+((Mi*inv(Mi, p_mod[i]))%p*a[i])%p)%p;
}
ret = (ret%p+p)%p;
return ret;
} LL work(LL x, LL y)
{
REP(i, , cnt)
{
pa t1 = calc(i, x), t2 = calc(i, y), t3 = calc(i, x-y);
a[i] = power(p_num[i], t1.fi-t2.fi-t3.fi, p_mod[i]);
a[i] = (((a[i]*t1.se)%p_mod[i]*inv(t2.se, p_mod[i]))%p_mod[i]*inv(t3.se, p_mod[i]))%p_mod[i];
}
return CRT();
} int main()
{
// freopen("a.in", "r", stdin);
// freopen("a.out", "w", stdout);
LL n, m, w[], sum = ;
scanf("%lld %lld %lld", &p, &n, &m);
prepare();
REP(i, , m) scanf("%lld", &w[i]), sum += w[i];
if (sum > n) { puts("Impossible"); return ; }
LL ans = work(n, sum);
REP(i, , m)
ans = (ans*work(sum, w[i]))%p, sum -= w[i];//, printf("%lld\n", ans);
ans = (ans+p)%p;
printf("%lld\n", ans);
return ;
}
BZOJ 2142 礼物 组合数学 CRT 中国剩余定理的更多相关文章
- NOI 2018 屠龙勇士 (拓展中国剩余定理excrt+拓展欧几里得exgcd)
		题目大意:略 真是一波三折的一道国赛题,先学了中国剩余定理,勉强看懂了模板然后写的这道题 把取出的宝剑攻击力设为T,可得Ti*x=ai(mod pi),这显然是ax=c(mod b)的形式 这部分用e ... 
- gcd,扩展欧几里得,中国剩余定理
		1.gcd: int gcd(int a,int b){ ?a:gcd(b,a%b); } 2.中国剩余定理: 题目:学生A依次给n个整数a[],学生B相应给n个正整数m[]且两两互素,老师提出问题: ... 
- 【bzoj3782】上学路线  dp+容斥原理+Lucas定理+中国剩余定理
		题目描述 小C所在的城市的道路构成了一个方形网格,它的西南角为(0,0),东北角为(N,M).小C家住在西南角,学校在东北角.现在有T个路口进行施工,小C不能通过这些路口.小C喜欢走最短的路径到达目的 ... 
- acm数论之旅--中国剩余定理
		ACM数论之旅9---中国剩余定理(CRT)(壮哉我大中华╰(*°▽°*)╯) 中国剩余定理,又名孙子定理o(*≧▽≦)ツ 能求解什么问题呢? 问题: 一堆物品 3个3个分剩2个 5个5个分剩3个 ... 
- RSA遇上中国剩余定理
		1.Introduction 最近读论文刚好用到了这个,之前只是有耳闻,没有仔细研究过,这里就好好捋一下,会逐步完善 不过貌似CRT(中国剩余定理)的实现更容易被攻击 2. RSA: Overview ... 
- 卢卡斯定理&&中国剩余定理
		卢卡斯定理(模数较小,且是质数) 式子C(m,n)=C(m/p,n/p)*C(m%p,n%p)%p 至于证明(我也不会QAQ,只要记住公式也该就好了). 同时卢卡斯定理一般用于组合数取模上 1.首先当 ... 
- 《孙子算经》之"物不知数"题:中国剩余定理
		1.<孙子算经>之"物不知数"题 今有物不知其数,三三数之剩二,五五数之剩七,七七数之剩二,问物几何? 2.中国剩余定理 定义: 设 a,b,m 都是整数. 如果 m ... 
- POJ 1006 中国剩余定理
		#include <cstdio> int main() { // freopen("in.txt","r",stdin); ; while(sca ... 
- [TCO 2012 Round 3A Level3] CowsMooing (数论,中国剩余定理,同余方程)
		题目:http://community.topcoder.com/stat?c=problem_statement&pm=12083 这道题还是挺耐想的(至少对我来说是这样).开始时我只会60 ... 
随机推荐
- 创建spring boot项目
			一.创建项目 1.输入https://start.spring.io/ 2.填写group.artifact 3.选择依赖的jar 4.点击创建项目 二.导入项目 1.eclipse的package ... 
- Python subprocess- call、check_call、check_output
			简介 subprocess模块用来创建新的进程,连接到其stdin.stdout.stderr管道并获取它们的返回码.subprocess模块的出现是为了替代如下旧模块及函数:os.system.os ... 
- python网络编程-socket“粘包”(小数据发送问题)
			一:什么是粘包 “粘包”, 即服务器端你调用时send 2次,但你send调用时,数据其实并没有立刻被发送给客户端,而是放到了系统的socket发送缓冲区里,等缓冲区满了.或者数据等待超时了,数据才会 ... 
- python基础-类的起源
			Python中一切事物都是对象. class Foo(object): def __init__(self,name): self.name = name f = Foo("alex&quo ... 
- Codeforces 801C Voltage Keepsake(二分枚举+浮点(模板))
			题目链接:http://codeforces.com/contest/801/problem/C 题目大意:给你一些电器以及他们的功率,还有一个功率一定的充电器可以给这些电器中的任意一个充电,并且不计 ... 
- 一步一步学习IdentityServer4 (7) IdentityServer4成功配置全部配置
			auth.liyouming.com 全部配 public class Startup { public Startup(IConfiguration configuration) { Configu ... 
- InterSystems Ensemble学习笔记(一) Ensemble介绍及安装
			系列目录 InterSystems Ensemble学习笔记(一) Ensemble介绍及安装InterSystems Ensemble学习笔记(二) Ensemble创建镜像, 实现自动故障转移 一 ... 
- Phoenix的安装使用与SQL查询HBase
			一. Phoenix的简介 1. 什么是phoenix 现有hbase的查询工具有很多如:Hive,Tez,Impala,Shark/Spark,Phoenix等.今天主要说Phoenix.phoen ... 
- Spark(二)CentOS7.5搭建Spark2.3.1分布式集群
			一 下载安装包 1 官方下载 官方下载地址:http://spark.apache.org/downloads.html 2 安装前提 Java8 安装成功 zookeeper 安 ... 
- mac系统编译安装ImageMagick7.0.1-3
			1.下载源码包: git clone http://git.imagemagick.org/repos/ImageMagick.git 2.编译安装: cd ImageMagick/ ./config ... 
