1 条题解
-
6
长度为 时,合并后的每项次数分别为
长度为 时,合并后的每项次数分别为
长度为 时,合并后的每项次数分别为
长度为 时,合并后的每项次数分别为
由数学归纳法可以得到,最后的每项次数分别为 $\binom {n-1} 0,\binom {n-1} 1,\binom {n-1} 2,\cdots,\binom {n-1} {n-1}$
所以为了求解 $\displaystyle \prod_{i=1}^n a_i^{\binom {n-1}i}\bmod P$ ,只需要对组合数模 ,最后跑快速幂合并即可
由于组合数的模数不是质数,不能直接由逆元推得,可以考虑使用 exLucas,不过那玩意儿难码。
考虑到组合数的递推式 ,而结果恒为整数。故实际上组合数递推过程中除去的结果一定为剩余部分的一个因子
考虑
将组合数分为三个部分维护: 的指数、 的指数和剩余的部分
作乘法的时候,前两者为相加,后者为乘积
作除法的时候,前两者为相减,后者为乘上逆元(逆元直接取 指数即可)
查询值的时候暴力跑一下快速幂即可
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<ll, ll> pii; typedef double db; #define fi first #define se second const int P=1e9+7; inline ll fpow(ll a, ll x, ll mod) { ll ans=1; for(;x;x>>=1,a=a*a%mod) if(x&1) ans=ans*a%mod; return ans; } int p[2]={2, P>>1}, phi=p[1]-1; struct exnum{ int x, cnt[2]; exnum() { x=0; cnt[0]=cnt[1]=0; } exnum(int val_) { cnt[0]=cnt[1]=0; for(int i=0; i<2; ++i) while(val_%p[i]==0) ++cnt[i], val_/=p[i]; x=val_; } exnum(int x_, int c0_, int c1_):x(x_) { cnt[0]=c0_; cnt[1]=c1_; } inline int val() const { return fpow(p[0], cnt[0], P-1)*fpow(p[1], cnt[1], P-1)%(P-1)*x%(P-1); } }; inline exnum operator * (const exnum &a, const exnum &b) { return exnum((ll)a.x*b.x%(P-1), a.cnt[0]+b.cnt[0], a.cnt[1]+b.cnt[1]); } inline exnum operator / (const exnum &a, const exnum &b) { return exnum((ll)a.x*fpow(b.x, phi-1, P-1)%(P-1), a.cnt[0]-b.cnt[0], a.cnt[1]-b.cnt[1]); } inline exnum operator * (const exnum &a, int b) { return a*exnum(b); } inline exnum operator / (const exnum &a, int b) { return a/exnum(b); } int main(){ ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); int n, res=1; cin>>n; exnum comb(1); for(int i=1, a; i<=n; ++i) { cin>>a; res=(ll)res*fpow(a, comb.val(), P)%P; if(i<n) comb=comb*(n-i)/i; } cout<<res; cout.flush(); return 0; }
- 1
信息
- ID
- 87
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 5
- 标签
- 递交数
- 117
- 已通过
- 44
- 上传者