排列组合、crt、费马小定理,容斥原理,lucas定理,组合数取模
一些公式&定理
\(lucas\)定理
\(C_n^m \equiv C_{n/p}^{m/p}\times C_{n\%p}^{m\%p}(mod\;p)\)
代码
int lucas(int n,int m,int p){
if(m>n)return 0;
if(m==0)return 1;
if(n<p&&m<p)return 1ll*jc[n]*inv[m]%p*inv[n-m]%p;
return lucas(n/p,m/p,p)*lucas(n%p,m%p,p)%p;
}
错排
\(f[n]=(n-1)*(f[n-1]+f[n-2])\)
考虑加入一个元素\(n\),通过一步操作得到错排
-
前\(n-1\)个数是错排,\(n\)随便交换一个,方案数\((n-1)*f[n-1]\)
-
前\(n-1\)个数有一个在原位置,共\(n-1\)种可能,剩下的数构成错排\(f[n-2]\),\(n\)只能和它交换,方案数\((n-1)*f[n-2]\)
-
前\(n-1\)个数有两个或以上个数在原位置,一步无法得到错排
加起来即可
crt 中国剩余定理
求解
\(\begin{cases} x &\equiv a_1 \pmod {n_1} \\ x &\equiv a_2 \pmod {n_2} \\ &\vdots \\ x &\equiv a_k \pmod {n_k} \\ \end{cases}\)
其中\(n_i\)两两互质
-
计算\(P\),为所有\(n_i\)的乘积
-
计算\(c_i=P/n_i\),以及\(c_i^-1(mod\;n_i)\)
-
答案\(x=\sum_{i=1}^k a_ic_i c_i^{-1} \pmod P\)
证明,\(x\%n_i时,其他的因为c_j的存在一定\equiv0,只有a_i留下,并且c_ic_i^{-1}\equiv 1\)所以得到了需要的答案
严谨过程

code
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
ll a[15],p[15],m[15],inv[15];
ll slow(ll x,ll y,ll mod){
ll ans=0;
for(;y;y>>=1,x=(x+x)%mod)if(y&1)ans=(ans+x)%mod;
return ans;
}
ll exgcd(ll a,ll b,ll &x,ll &y){
if(b==0){
x=1;y=0;
return a;
}
ll gcd=exgcd(b,a%b,y,x);
y-=a/b*x;
return gcd;
}
ll INV(ll a,ll b){
ll x,y;
ll gcd=exgcd(a,b,x,y);
return (x%b+b)%b;
}
int main()
{
int n;scanf("%d",&n);
for(int i=1;i<=n;++i)scanf("%lld %lld",&p[i],&a[i]);
ll P=1;for(int i=1;i<=n;++i)P*=p[i];
for(int i=1;i<=n;++i)m[i]=P/p[i];
for(int i=1;i<=n;++i)inv[i]=INV(m[i],p[i]);
ll x=0;
for(int i=1;i<=n;++i)x=(x+slow(slow(a[i],m[i],P),inv[i],P))%P;
printf("%lld\n",x);
return 0;
}
excrt
使用扩展欧几里得算法两两合并
\(\begin{cases} x &\equiv a_1 \pmod {n_1} \\ x &\equiv a_2 \pmod {n_2} \\ \end{cases}\)
\(x=a_1+pn_1=a_2-qn_2\)
\(pn_1+qn_2=a_2-a_1(mod\;lcm)\)
code
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
ll res[100005],p[100005];
ll exgcd(ll a,ll b,ll &x,ll &y){
if(b==0){
x=1;y=0;
return a;
}
ll gcd=exgcd(b,a%b,y,x);
y-=a/b*x;
return gcd;
}
ll china(int n){
ll a,b,c,x,y,gcd,ans=res[1];
a=p[1];
for(int i=2;i<=n;++i){
b=p[i];c=res[i]-ans;
int gcd=exgcd(a,b,x,y);
if(c%gcd!=0)return -1;
x=(x*(c/gcd)%(b/gcd)+(b/gcd))%(b/gcd);
ans=x*a+ans;
a=a/gcd*b;
}
return ans;
}
int main()
{
int n;
while(scanf("%d",&n)!=EOF){
for(int i=1;i<=n;++i)scanf("%lld %lld",&p[i],&res[i]);
if(n==1){printf("%lld\n",res[1]);continue;}
printf("%lld\n",china(n));
}
return 0;
}
exlucas
跟lucas没啥关系。。
根据唯一分解定定理
\(p={q_1}^{\alpha_1}\cdot{q_2}^{\alpha_2}\cdots{q_r}^{\alpha_r}\)
求解
\(\left\{ \begin{aligned} a_1\equiv \displaystyle\binom{n}{m}&\pmod {{q_1}^{\alpha_1}}\\ a_2\equiv \displaystyle\binom{n}{m}&\pmod {{q_2}^{\alpha_2}}\\ &\cdots\\ a_r\equiv \displaystyle\binom{n}{m}&\pmod {{q_r}^{\alpha_r}}\\ \end{aligned} \right.\)
就可以使用crt合并
现在考虑计算
\(\displaystyle a_i=\binom{n}{m}\bmod {q_i}^{\alpha_i}\)
无法直接计算,如果移除因子\(q\)最后统一计算呢
\(\frac{\frac{n!}{q^x}}{\frac{m!}{q^y}\frac{(n-m)!}{q^z}}q^{x-y-z} \bmod q^k\)
现在考虑求
\(\frac{n!}{q^x}\bmod q^k\)

显然现在就是求这东西
反过来,展开有
\(n! = q^{\left\lfloor\frac{n}{q}\right\rfloor} \cdot \left(\left\lfloor\frac{n}{q}\right\rfloor\right)! \cdot {\left(\prod_{i,(i,q)=1}^{q^k}i\right)}^{\left\lfloor\frac{n}{q^k}\right\rfloor} \cdot \left(\prod_{i,(i,q)=1}^{n\bmod q^k}i\right)\)
后面那两个奇怪的东西就是\((n!)_p\),只不过分成了两部分
为什么可以这样分?
因为\(a\equiv a+q^k(mod\;q^k)\)
\(q^{\left\lfloor\frac{n}{q}\right\rfloor}\)这东西不用求
\(\left(\left\lfloor\frac{n}{q}\right\rfloor\right)!\)递归求解
剩下那个暴力就行
code
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
ll w[105];
ll qpow(ll x,ll y,ll mod){
ll ans=1;
for(;y;y>>=1,x=1ll*x*x%mod)if(y&1)ans=1ll*ans*x%mod;
return ans;
}
ll exgcd(ll a,ll b,ll &x,ll &y){
if(b==0){
x=1;y=0;
return a;
}
ll gcd=exgcd(b,a%b,y,x);
y-=a/b*x;
return gcd;
}
ll inv(ll a,ll p){
ll x,y;
ll gcd=exgcd(a,p,x,y);
return (x%p+p)%p;
}
ll get_f(ll n,ll p,ll pk){
if(!n)return 1;
ll res=1,ls=n%pk;
for(ll i=2;i<=ls;++i)if(i%p)res=1ll*res*i%pk;
ll num=res;
for(ll i=ls+1;i<pk;++i)if(i%p)res=1ll*res*i%pk;
return 1ll*get_f(n/p,p,pk)*qpow(res,n/pk,pk)%pk*num%pk;
}
ll get_c(ll n,ll m,ll p,ll pk){
ll res=0,d=n-m;
for(ll i=p;i<=n;i*=p)res+=n/i;
for(ll i=p;i<=m;i*=p)res-=m/i;
for(ll i=p;i<=d;i*=p)res-=d/i;
return 1ll*qpow(p,res,pk)*get_f(n,p,pk)%pk*inv(get_f(m,p,pk),pk)%pk*inv(get_f(d,p,pk),pk)%pk;
}
ll exlucas(ll n,ll m,ll p){
if(m==n)return 1;
ll lp=p;ll ans=0;
for(ll i=2;i*i<=lp;++i){
if(lp%i)continue;
ll pk=1;while(lp%i==0){lp/=i,pk*=i;}
ll c=p/pk;
ans=(ans+1ll*get_c(n,m,i,pk)*c%p*inv(c,pk)%p)%p;
}
if(lp!=1){
ll c=p/lp;
ans=(ans+1ll*get_c(n,m,lp,lp)*c%p*inv(c,lp)%p)%p;
}
return ans;
}
int main(){
ll mod,n,m;
scanf("%lld%lld%lld",&mod,&n,&m);
for(ll i=1;i<=m;++i)scanf("%lld",&w[i]);
ll sum=0;for(ll i=1;i<=m;++i)sum+=w[i];
if(sum>n)printf("Impossible\n");
else{
ll ans=exlucas(n,sum,mod);
for(ll i=1;i<=m;++i){
ans=1ll*ans*exlucas(sum,w[i],mod)%mod;
sum-=w[i];
}
printf("%lld\n",ans%mod);
}
return 0;
}
题目乱写
A. 排队
两种情况
- 老师中间是男生
男生排列\(A_n^n\)
老师插空\(A_{n+1}^2\)
女生插空\(A_{n+3}^m\)
- 老师中间是女生
男生排列\(A_n^n\)
老师+一个女生整体法\(C_{n+1}^1*A_2^2\)
剩下女生插空\(A_{n+2}^{m-1}\)
打个高精
B. combination
\(lucas\)模板,关于\(lucas\)的证明我没看明白,先不管了
C. 排列计数
基本是错排板子,加一个简单组合数就行了
D. Perm 排列计数
把大小关系画出来,发现是个二叉堆,然后组合数+树DP
E. 集合计数
容斥
\(f[i]\)表示交集至少\(i\)个的方案数
首先钦定这\(i\)个交集\(c_n^i\)
剩下的\(n-k\)个数能构成\(2^{n-k}\)个集合,每个集合都可以选或不选,去掉空集\(2^{2^{n-k}}-1\)
然后容斥一下就行了
F. 牡牛和牝牛
简单DP,有排列组合做法,但没必要
G BZOJ 4403序列统计
首先\(l,r\)是假的,只有\(r-l\)有用
然后枚举长度,隔板法处理
H DZY Loves Math II
题意转化\(R-L\)个不同元素,取\(1-N\)个元素,有多少种取法,直接组合数就行
x=
然后问题就是一个背包了...吗?
发现值域太大,完全跑不出来
但是可以发现
\(n=k*S+a\)
注意\(a\)不一定小于\(S\)
分成两部分求解
\(k*S\),每个\(S\)可以由\(S/p_i\)个\(p_i\)构成,每个\(p_i\)都有可能,用隔板法就是\(c_{k+cnt-1}^{cnt-1}\)
\(a\)这部分直接背包就行,但是注意由于上面的计算,这里需要保证每个\(p_i\)使用次数小于\(S/p_i\)
多重背包?其实不用,完全背包再加一个\(dp[i]-=dp[i-s]\)就行了
I. 虔诚的墓主人
这题我觉得是扫描线,但是严重怀疑不是正解,然后,,,就是扫描线,加上一个简单的组合数就行
J. 地精部落
妙极了,不会做的蓝题系列
首先看性质
- 在一个数列中,若\(i\)与\(i+1\)不相邻,直接交换这两个数字就可以组成一个新的数列
- 把波动数列中的每个数字\(a_i\)变成\((n+1)-a_i\)会得到互补的数列,即且新数列的山峰与山谷情况相反
- 数列有对称性
状态设计
\(dp[i][j]\)表示选择\(1-i\)这些数字,第一位是\(j\)并且是山峰的方案数
转移
因为性质\(1\)有\(dp[i][j]+=dp[i][j-1]\)(\(dp[i][j-1]\)中,因为\(j-1\)是峰,\(j\)一定不与\(j-1\)相邻)
如果\(j\)与\(j-1\)相邻,那么把\(j\)放到以\(j-1\)为开头并且\(j-1\)是谷的数列前,因为性质2,那么有\(dp[i][j]+=dp[i-1][i+1-j]\)
答案
因为性质3,答案就是\(\sum_{i=1}^n dp[n][i]*2\)
K. 看电影
这题应该放到高精题单里!
假设存在一个\(k+1\)号座位,然后把座位\(k+1\)与座位\(1\)连上,这样每个人都有座位,合法的方案里第\(k+1\)个座位应该是没有人的,枚举哪个位置是\(k+1\)断开这个环即可
合法方案数\((k+1)^{n-1}\times (k-n+1)\)
总方案数\(k^n\)
然后就是高精了
L. 曹冲养猪
crt板子
M. Strange Way to Express Integers
excrt板子
N. 礼物
式子好推就是\(C_n^{sum}\times C_{sum}^{a_1}\times C_{sum-a_1}^{a_2}....\)
然后就是exlucas板子
O. 古代猪文
欧拉定理+lucas+crt
P. Per
可重集的排列+康拓展开+逆元,感觉有点exlucas的思想

浙公网安备 33010602011771号