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

100 4 2 1 2

Sample Output

12

【样例说明】
下面是对样例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 中国剩余定理的更多相关文章

  1. NOI 2018 屠龙勇士 (拓展中国剩余定理excrt+拓展欧几里得exgcd)

    题目大意:略 真是一波三折的一道国赛题,先学了中国剩余定理,勉强看懂了模板然后写的这道题 把取出的宝剑攻击力设为T,可得Ti*x=ai(mod pi),这显然是ax=c(mod b)的形式 这部分用e ...

  2. gcd,扩展欧几里得,中国剩余定理

    1.gcd: int gcd(int a,int b){ ?a:gcd(b,a%b); } 2.中国剩余定理: 题目:学生A依次给n个整数a[],学生B相应给n个正整数m[]且两两互素,老师提出问题: ...

  3. 【bzoj3782】上学路线 dp+容斥原理+Lucas定理+中国剩余定理

    题目描述 小C所在的城市的道路构成了一个方形网格,它的西南角为(0,0),东北角为(N,M).小C家住在西南角,学校在东北角.现在有T个路口进行施工,小C不能通过这些路口.小C喜欢走最短的路径到达目的 ...

  4. acm数论之旅--中国剩余定理

    ACM数论之旅9---中国剩余定理(CRT)(壮哉我大中华╰(*°▽°*)╯)   中国剩余定理,又名孙子定理o(*≧▽≦)ツ 能求解什么问题呢? 问题: 一堆物品 3个3个分剩2个 5个5个分剩3个 ...

  5. RSA遇上中国剩余定理

    1.Introduction 最近读论文刚好用到了这个,之前只是有耳闻,没有仔细研究过,这里就好好捋一下,会逐步完善 不过貌似CRT(中国剩余定理)的实现更容易被攻击 2. RSA: Overview ...

  6. 卢卡斯定理&&中国剩余定理

    卢卡斯定理(模数较小,且是质数) 式子C(m,n)=C(m/p,n/p)*C(m%p,n%p)%p 至于证明(我也不会QAQ,只要记住公式也该就好了). 同时卢卡斯定理一般用于组合数取模上 1.首先当 ...

  7. 《孙子算经》之"物不知数"题:中国剩余定理

    1.<孙子算经>之"物不知数"题 今有物不知其数,三三数之剩二,五五数之剩七,七七数之剩二,问物几何? 2.中国剩余定理 定义: 设 a,b,m 都是整数.  如果 m ...

  8. POJ 1006 中国剩余定理

    #include <cstdio> int main() { // freopen("in.txt","r",stdin); ; while(sca ...

  9. [TCO 2012 Round 3A Level3] CowsMooing (数论,中国剩余定理,同余方程)

    题目:http://community.topcoder.com/stat?c=problem_statement&pm=12083 这道题还是挺耐想的(至少对我来说是这样).开始时我只会60 ...

随机推荐

  1. imperva 网管替换

    事情是这样的 某某银行的imperva DAM审计设备出现蜂鸣的响声.经检查电源没有问题,怀疑是硬盘坏了 . 然后我就去底层查看 运行命令 :impctl platform storage raid ...

  2. Linux XOR.DDoS样本取证特征与清除

    一.取证特征 1)获取进程ID 使用top命令,查看占用内存率最高的十位随机名称进程名(示例:进程名pygdykcrqf) 2)获取进程对应路径 Linux 在启动一个进程时,系统会在/proc下创建 ...

  3. Intent 对象在 Android 开发中的应用

    转自(http://www.ibm.com/developerworks/cn/opensource/os-cn-android-intent/) Android 是一个开放性移动开发平台,运行在该平 ...

  4. dorado 的学习位置、控件使用方法查找、示例演示地址

    dorado的学习位置: http://wiki.bsdn.org/display/dorado7/Project+Home dorado的控件使用方法查找: http://dorado7.bsdn. ...

  5. NuGet套件还原步骤(以vs2012为例)

    下载别人的范例,出现由于Nuget套件不存在而无法启动时: 效果如下图: 步骤如下: 1.点击 项目->启用NuGet程序包还原 2.点击下图中的是 3.点击下图中的确定 4.效果如图: . 5 ...

  6. 如何提高单片机Flash的擦写次数

    所谓提高flash的擦写次数,并不是真正的提高flash擦写次数,而是通过以"空间换时间"概念,在软件上实现“操作的次数大于其寿命”.详见链接: http://bbs.eeworl ...

  7. APUE-文件和目录(二)函数access,mask,chmod和粘着位

    4.7 函数access和faccessat 当一个进程使用了设置用户ID和设置组ID作为另一个用户(或者组)运行时,这时候有效用户(组)ID和实际用户(组)ID不一样,但进程仍然希望测试实际用户(组 ...

  8. TCP包服务器接受程序

    //功能:客户端发送TCP包,此程序接受到,将字母转换为大写,在发送到客户端#include <stdio.h>#include <sys/socket.h>#include ...

  9. 使用django发送邮件时的连接超时问题解决

    一.报错 研究报错半天,没看出代码有什么毛病,就是发送邮件时连接超时,发送邮件的连接用户名密码都没有错误,于是就网上各种查... 终于皇天不负有心人,找到答案了.. 在服务器上输入telnet smt ...

  10. Ansible实战:部署分布式日志系统

    本节内容: 背景 分布式日志系统架构图 创建和使用roles JDK 7 role JDK 8 role Zookeeper role Kafka role Elasticsearch role My ...