QBXT游记 | Day3 Moring
组合数求模
也就是求 C(n,m)%p=?
Lv.1
其中n,m<=2000,p为任意整数
根据题意大约能看出是\(O(n^2)\)的算法可求
我们知道C(n,m)=[C(n-1,m-1)+C(n-1,m)]%p
所以我们能知道这个数最大能到达杨辉三角的第2000行,可以直接预处理的时候把每个数%p即可
Lv.2
其中n,m<=106,p>=109且为质数
根据定义柿:C(n,m)%p=\(\frac{n!}{n!(n-m)!}\)%p=n!%p x (m!)-1%p x (n-m)-1%p
因为p是质数,所以对于这个柿子,任何数的逆元一定存在
Lv.3
其中n,m<=106,p<=2000且为质数
因为n,m都可能比p大,所以刚才那个做法里面的逆元不存在
这里引入一个新的定理:卢卡斯定理
对于n和m,已知p为质数,n和m都能表示为p进制:\(n=n_k+n_{k-1}+\cdots+n_1\),m同理(这里要保证位数能一致,不够的加上前导0
内容:参见OIwiki,经过lucas分解之后就能得到一个p进制的形式,那样的话逆元是存在的,就可以用Lv2的方法求了
LV.4
其中n,m<=106,p=p1*p2,p1和p2都<=2000且为质数
能知道C(n,m)%p1=a1,C(n,m)%p2=a2(利用刚才的方法)
可以使用连理方程组后Excrt求解
x%p1=a1
x%p2=a2
👇
x%p1p2=a3
Lv.4 Pro
把p扩展至p=p1p2p3p4...pk,pi<=2000
一样对每个质数使用Lv3的方法取模,然后用Excrt合并求解
当然有些更加的离谱的数据是处理不了的
组合数例题
P1
Describe
- 要求你把x拆成k个不同的组合数之和
- 只要C(n1 n2)或者C(m1 m2) 不同,就叫做不同的组合数
- 任意输出一种方案
- x<=109,k<=103
Solution
x=1+1+1+1+1+1+1+1+1...+1+1+(x-k+1)(一共有k-1个1)
=C(0,0)+C(1,0)+C(2,0)...+C(k-2,0)+C(x-k+1,1) (C(n,1)=n)
代码如下(洛谷P4369,noip.ac的数学3的第一题)
#include <bits/stdc++.h>
#define Heriko return
#define Deltana 0
#define S signed
#define U unsigned
#define LL long long
#define R register
#define I inline
#define D double
#define LD long double
#define mst(a,b) memset(a,b,sizeof(a))
#define ON std::ios::sync_with_stdio(false)
using namespace std;
I void fr(LL &x)
{
LL f=1;char c=getchar();
x=0;
while(c<'0'||c>'9')
{
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9')
{
x=(x<<3)+(x<<1)+c-'0';
c=getchar();
}
x*=f;
}
void fw(LL x)
{
if(x<0) x=-x,putchar('-');
if(x>9) fw(x/10);
putchar('0'+x%10);
}
S main()
{
LL x,k;
fr(x),fr(k);
for(R LL i=1;i<k;i++) fw(i),putchar(' '),fw(0),putchar('\n');
fw(x-k+1);putchar(' ');fw(1);putchar('\n');
Heriko Deltana;
}
别看代码挺长,实际上是我缺省源比较长
P2
比较C(n1,m1),C(n2,m2)的大小关系
如果C(n1,m1)<C(n2,m2),那么我们可以推出log C(n1,m1)<log C(n2,m2)
因为这两者都大于1,所以可以直接根据对数函数来推出这柿子
这里用一个res来存储log i的阶乘,Code大体如下
for(R LL i=1;i<=n;i++) res[i]=res[i-1]+log[i];
//res[i]=log[i]!
log[C[n][m]]=res[n]-res[n-m]-res[m];
P2 Pro
Describe
- 找到k个不同的组合数使得这k个组合数的和最大
- 其中 C(a,b) 满足 0<=b<=a<=n
- n<=106 k<=105
Solution
k=1时,我们观察杨辉三角可以发现,每行最大的组合数都在最后一行的中间,即为 C(n,n/2)
k=2时,我们可以发现次大的组合数一定在最大的组合数周围(也就是说一定在最大的左上右上(奇数行)/正上(偶数行)/左右)
我们考虑维护一个堆(使用优先队列priority_queue)
找到最大的扔进去,然后把他周围的数都扔进堆
然后每次取出最大的,把它的周围扔进去,就可以求出前k大的组合数,然后求和即可
大约的就是P2加上一个堆
P3
Describe
求
Solution
C(n,m)=C(n-1,m-1)+C(n-1,m)=C(n-2,m-2)+2C(n-2,m-1)+C(n-2,m)
=C(n-3,m-3)+3C(n-3,m-2)+...
=1...+4...+6...+4...+1...
实际上可以发现系数也是组合数
抽屉原理
把n+1个物体放到n个抽屉里面,则至少有一个抽屉含有两个或两个以上的物品
P4
Describe
- 给定N个数,要求选择任意多个数,使他们的和为c的倍数
- c<=N<=105
Solution
发现c可能等于N
把抽屉编号为0,1,2,3,4,5,6,...,c-1
每个抽屉对应的是 和%c=i
用sum[i]来代表前i个数的和,我们能算出0~n的前缀和,所以一共有n+1个sum
如果sum[i]%c=k,那么我们把他放到抽屉里面,此时是有n+1个物品,c个抽屉
然后根据抽屉原理,一定能找到某个抽屉里面有两个sum(这两个前缀和一定不相同),那么这2个前缀和相减就是我们要求的区间
P5
Describe
- 平面上有N个点,要求用三个边长为L的正方形覆盖全部的点(每个正方形都是横平竖直的),求最小的L
- N<= 5*104
Solution
先考虑能否用三个L x L 的正方形能否覆盖所有点
那么肯定是最边界的点(x最大的,y最大的,x最小的,y最小的)会对L影响最大
三个正方形,四个点,那么说明只要有一个正方形放角上(要覆盖两个点)
那么先暴力枚举让那个边角上的满足条件,然后再去枚举其他的正方形去在覆盖剩下的2个极点,然后再去暴力枚举能覆盖所有点的边长
复杂度是\(O(4n\log n)\)
容斥原理
以下是我上课手打的一个非\(\LaTeX\)的柿子,非常的乱
|A1∪A2∪A3∪...An|=|A1|+|A2|+...+|An|-|A1∩A2|-|A2∩A3|-...-|An-1 ∩ An|+|A1∩A2∩A3|+|A2∩A3∩A4|+...+|An-2 ∩ An-1 ∩ An|...
并且这个柿子非常简陋,建议看OI Wiki上的柿子
P6
Describe
有n个夫妻,他们坐成一圈,要求一对夫妻之间不能相邻
Solution
强制绑定一对夫妻相邻
(2N-1)! - C(N,1) x (2N-2)! x 2 + C(N,2) x (2N-3)! x 22-C(N,3) x (2N-1)! x 23 ....
=\(\sum\limits_{i=0}^N (-1)^i*C(N,i)*(2N-i-1)!*2!\)
实际上这两部分差不多的,下面的是课堂笔记,拿出来作为一个参考
实际上这两部分差不多的原因是我懒得改了
上课Craft笔记部分:
组合数求模
C(n,m)%p=?
Lv.1
其中n,m<=2000,p为任意整数
根据题意大约能看出是\(O(n^2)\)的算法可求
我们知道C(n,m)=[C(n-1,m-1)+C(n-1,m)]%p
所以我们能知道这个数最大能到达杨辉三角的第2000行,可以直接预处理的时候把每个数%p即可
Lv.2
其中n,m<=106,p>=109且为质数
根据定义柿:C(n,m)%p=\(\frac{n!}{n!(n-m)!}\)%p=n!%p x (m!)-1%p x (n-m)-1%p
因为p是质数,所以对于这个柿子,任何数的逆元一定存在
Lv.3
其中n,m<=106,p<=2000且为质数
因为n,m都可能比p大,所以刚才那个做法里面的逆元不存在
这里引入一个新的定理:卢卡斯定理
对于n和m,已知p为质数,n和m都能表示为p进制:\(n=n_k+n_{k-1}+\cdots+n_1\),m同理(这里要保证位数能一致,不够的加上前导0
内容:参见OIwiki,经过lucas分解之后就能得到一个p进制的形式,那样的话逆元是存在的,就可以用Lv2的方法求了
LV.4
其中n,m<=106,p=p1*p2,p1和p2都<=2000且为质数
能知道C(n,m)%p1=a1,C(n,m)%p2=a2(利用刚才的方法)
可以使用连理方程组后Excrt求解
x%p1=a1
x%p2=a2
👇
x%p1p2=a3
Lv.4 Pro
把p扩展至p=p1p2p3p4...pk,pi<=2000
一样对每个质数使用Lv3的方法取模,然后用Excrt合并求解
当然有些更加的离谱的数据是处理不了的
组合数例题
P1
Describe
- 要求你把x拆成k个不同的组合数之和
- 只要C(n1 n2)或者C(m1 m2) 不同,就叫做不同的组合数
- 任意输出一种方案
- x<=109,k<=103
Solution
x=1+1+1+1+1+1+1+1+1...+1+1+(x-k+1)(一共有k-1个1)
=C(0,0)+C(1,0)+C(2,0)...+C(k-2,0)+C(x-k+1,1) (C(n,1)=n)
代码如下(洛谷P4369,noip.ac的数学3的第一题)
#include <bits/stdc++.h>
#define Heriko return
#define Deltana 0
#define S signed
#define U unsigned
#define LL long long
#define R register
#define I inline
#define D double
#define LD long double
#define mst(a,b) memset(a,b,sizeof(a))
#define ON std::ios::sync_with_stdio(false)
using namespace std;
I void fr(LL &x)
{
LL f=1;char c=getchar();
x=0;
while(c<'0'||c>'9')
{
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9')
{
x=(x<<3)+(x<<1)+c-'0';
c=getchar();
}
x*=f;
}
void fw(LL x)
{
if(x<0) x=-x,putchar('-');
if(x>9) fw(x/10);
putchar('0'+x%10);
}
S main()
{
LL x,k;
fr(x),fr(k);
for(R LL i=1;i<k;i++) fw(i),putchar(' '),fw(0),putchar('\n');
fw(x-k+1);putchar(' ');fw(1);putchar('\n');
Heriko Deltana;
}
别看代码挺长,实际上是我缺省源比较长
P2
比较C(n1,m1),C(n2,m2)的大小关系
如果C(n1,m1)<C(n2,m2),那么我们可以推出log C(n1,m1)<log C(n2,m2)
因为这两者都大于1,所以可以直接根据对数函数来推出这柿子
这里用一个res来存储log i的阶乘,Code大体如下
for(R LL i=1;i<=n;i++) res[i]=res[i-1]+log[i];
//res[i]=log[i]!
log[C[n][m]]=res[n]-res[n-m]-res[m];
P2 Pro
Describe
- 找到k个不同的组合数使得这k个组合数的和最大
- 其中 C(a,b) 满足 0<=b<=a<=n
- n<=106 k<=105
Solution
k=1时,我们观察杨辉三角可以发现,每行最大的组合数都在最后一行的中间,即为 C(n,n/2)
k=2时,我们可以发现次大的组合数一定在最大的组合数周围(也就是说一定在最大的左上右上(奇数行)/正上(偶数行)/左右)
我们考虑维护一个堆(使用优先队列priority_queue)
找到最大的扔进去,然后把他周围的数都扔进堆
然后每次取出最大的,把它的周围扔进去,就可以求出前k大的组合数,然后求和即可
大约的就是P2加上一个堆
P3
Describe
求
Solution
C(n,m)=C(n-1,m-1)+C(n-1,m)=C(n-2,m-2)+2C(n-2,m-1)+C(n-2,m)
=C(n-3,m-3)+3C(n-3,m-2)+...
=1...+4...+6...+4...+1...
实际上可以发现系数也是组合数
抽屉原理
把n+1个物体放到n个抽屉里面,则至少有一个抽屉含有两个或两个以上的物品
P4
Describe
- 给定N个数,要求选择任意多个数,使他们的和为c的倍数
- c<=N<=105
Solution
发现c可能等于N
把抽屉编号为0,1,2,3,4,5,6,...,c-1
每个抽屉对应的是 和%c=i
用sum[i]来代表前i个数的和,我们能算出0~n的前缀和,所以一共有n+1个sum
如果sum[i]%c=k,那么我们把他放到抽屉里面,此时是有n+1个物品,c个抽屉
然后根据抽屉原理,一定能找到某个抽屉里面有两个sum(这两个前缀和一定不相同),那么这2个前缀和相减就是我们要求的区间
P5
Describe
- 平面上有N个点,要求用三个边长为L的正方形覆盖全部的点(每个正方形都是横平竖直的),求最小的L
- N<= 5*104
Solution
先考虑能否用三个L x L 的正方形能否覆盖所有点
那么肯定是最边界的点(x最大的,y最大的,x最小的,y最小的)会对L影响最大
三个正方形,四个点,那么说明只要有一个正方形放角上(要覆盖两个点)
那么先暴力枚举让那个边角上的满足条件,然后再去枚举其他的正方形去在覆盖剩下的2个极点,然后再去暴力枚举能覆盖所有点的边长
复杂度是\(O(4n\log n)\)
容斥原理
|A1∪A2∪A3∪...An|=|A1|+|A2|+...+|An|-|A1∩A2|-|A2∩A3|-...-|An-1 ∩ An|+|A1∩A2∩A3|+|A2∩A3∩A4|+...+|An-2 ∩ An-1 ∩ An|...
P6
Describe
有n个夫妻,他们坐成一圈,要求一对夫妻之间不能相邻
Solution
强制绑定一对夫妻相邻
(2N-1)! - C(N,1) x (2N-2)! x 2 + C(N,2) x (2N-3)! x 22-C(N,3) x (2N-1)! x 23 ....
=\(\sum\limits_{i=0}^N (-1)^i*C(N,i)*(2N-i-1)!*2!\)