1 条题解
-
0
BZOJ 2313 分组 题解
前置知识
- 威尔逊定理;
- 中国剩余定理;
- 费马小定理(欧拉定理);
- 组合数学。
题意简化
给定 ,,设 为将 个数划分成多个大小一样的集合的方案数,求 。
题目分析
设 划分成的集合大小为 ,那么这时方案数就是:
$$\begin{aligned} & \frac{\prod_{i=1}^{\frac{n}{p}}\begin{pmatrix} ip \\ p \end{pmatrix}}{\frac{n}{p}!} \\ & = \frac{\prod_{i=1}^{\frac{n}{p}}\frac{(ip)!}{[(i-1)p]!p!}}{\frac{n}{p}!} \\ & = \frac{\prod_{i=1}^{\frac{n}{p}}\frac{(ip)!}{[(i-1)p]!}}{\frac{n}{p}!(p!)^{\frac{n}{p}}} \\ & = \frac{n!}{\frac{n}{p}!(p!)^{\frac{n}{p}}} \\ \end{aligned} $$而因为大小要相等,我们知道 肯定是 的约数,所以总方案数 就是:
$$k = \sum_{p|n}\frac{n!}{\frac{n}{p}!(p!)^{\frac{n}{p}}} $$设 那么最后求得的答案为:
$$m^{\sum_{p|n}\frac{n!}{\frac{n}{p}!(p!)^{\frac{n}{p}}}} \pmod P \\ $$而我们知道根据欧拉定理,这个大指数就可以降幂,变成形如下面的式子:
$$\begin{aligned} & m^{\sum_{p|n}\frac{n!}{\frac{n}{p}!(p!)^{\frac{n}{p}}}} \pmod P \\ & = m^{\sum_{p|n}\frac{n!}{\frac{n}{p}!(p!)^{\frac{n}{p}}}\pmod {\varphi{(P)}}} \pmod P \\ \end{aligned} $$同时我们又发现作为模数的 是一个质数,那么欧拉定理退化成费马小定理:
$$\begin{aligned} & m^{\sum_{p|n}\frac{n!}{\frac{n}{p}!(p!)^{\frac{n}{p}}}\pmod {\varphi{(P)}}} \pmod P \\ & = m^{\sum_{p|n}\frac{n!}{\frac{n}{p}!(p!)^{\frac{n}{p}}}\pmod {P-1}} \pmod P \\ \end{aligned} $$看着这个式子似乎还是不太好做,那我们想一下有什么与阶乘相关的数论知识:明显是威尔逊定理。但是又出现了一个问题,威尔逊定理要求模数是质数,而 明显不是质数,我们需要一种方法转换它,这时候就想到了性质非常契合的中国剩余定理:我们把 拆成几个质数 ,然后就可以通过下面的式子算出来:
设 是我们要求的指数, 是 降幂之后的值,则 ,它们满足以下线性同组方程组:
$$\forall i \in [1,n],p_i | (P-1) \\ \begin{cases} X \equiv y_1 \pmod {p_1} \\ X \equiv y_2 \pmod {p_2} \\ \cdots \\ X \equiv y_n \pmod {p_n} \\ \end{cases} $$那么我们对每个质数 分别把 求出来,最后再放到一起用中国剩余定理合并,就可以得出 。
我们处理完,发现 ,也就是说 。
那么我们只需要求出对于每个 ,$\frac{n!}{\frac{n}{p}!(p!)^{\frac{n}{p}}} \pmod {p_i}$ 的值是多少,容易发现这是威尔逊定理的模版。
CODE
#include<bits/stdc++.h> #define FOR(i,a,b) for(int i=(a);i<=(int)(b);++i) #define DOR(i,a,b) for(int i=(a);i>=(int)(b);--i) #define RCL(a,b,c,d) memset((a),(b),sizeof(c)*(d)) #define main Main();signed main(){ios::sync_with_stdio(0);cin.tie(0);return Main();}signed Main using namespace std; constexpr int N=1e4+10,MOD[5]= {999999599,2,13,5281,7283}; namespace Modular_Arithmetic { #define Toadd(a,b) ((a)=add((a),(b))) #define Tomul(a,b) ((a)=mul((a),(b))) #define toadd(x,a,b) ((a)=(x).add((a),(b))) #define tomul(x,a,b) ((a)=(x).mul((a),(b))) struct Modular { int MOD; int fac[N]; template<typename T1,typename T2>constexpr auto add(T1 a,T2 b) { return a+b>=MOD?a+b-MOD:a+b<0?a+b+MOD:a+b; } template<typename T1,typename T2>constexpr auto mul(T1 a,T2 b) { return (1ll*a*b%MOD+MOD)%MOD; } template<typename T,typename...Types>constexpr auto add(T a,Types... b) { return add(a,add(b...)); } template<typename T,typename...Types>constexpr auto mul(T a,Types... b) { return mul(a,mul(b...)); } int Pow(int a,int b) { int res=1; for(a%=MOD; b; b>>=1,Tomul(a,a))if(b&1)Tomul(res,a); return res; } int _Pow(int n) { int cnt=0; for(; n; n/=MOD,cnt+=n); return cnt; } int Inv(int x) { return Pow(x,MOD-2); } int Fac(int n) { int res=1; for(; n>1; Tomul(res,fac[n%MOD]),n/=MOD)if((n/MOD)&1)res=MOD-res; return res; } void Init() { fac[0]=1; FOR(i,1,MOD-1)fac[i]=mul(fac[i-1],i); } int Solve(int n,int m) { return _Pow(n)-_Pow(m)>_Pow(n/m)*m?0:mul(Fac(n),Inv(Fac(m)),Inv(Pow(Fac(n/m),m))); } } M[5]; void Init() { FOR(i,0,4) { M[i].MOD=MOD[i]; if(i)M[i].Init(); } } } using namespace Modular_Arithmetic; int Cas,n,m,ans,mod; int a[N]; vector<int> Divide(int x) { vector<int> vec; vec.clear(); for(int i=1; i*i<=x; ++i)if(x%i==0) { vec.push_back(i); if(i*i!=x)vec.push_back(x/i); } return sort(vec.begin(),vec.end()),vec; } signed Cmain() { cin>>n>>m,RCL(a,0,a,1); vector<int> factors=Divide(n); FOR(i,1,4)for(int &x:factors)toadd(M[i],a[i],M[i].Solve(n,x)); ans=a[4],mod=MOD[4]; DOR(i,3,1) { while(ans%MOD[i]!=a[i])ans+=mod; mod*=MOD[i]; } cout<<M[0].Pow(m,ans)<<endl; return 0; } signed main() { for(Init(),cin>>Cas; Cas; --Cas)Cmain(); return 0; }
后记
这是一道数论好题,难得地集齐了四大数论定理,当然还可以用扩展卢卡斯定理做(但我不会),值得拿来练手,加深印象,其中对中国剩余定理的运用也是我先前所不知道的,这道题对数论能力真的非常有帮助。
信息
- ID
- 1863
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 9
- 标签
- (无)
- 递交数
- 12
- 已通过
- 4
- 上传者