8.【题解】礼物
题解
\(\text{exlucas}\)(\(\text{恶心lucas}\))
- 首先 \(exlucas\) 跟 \(lucas\) 没半毛钱关系……
- \(exlucas\) 的思路是将不一定是质数的模数 \(P\) 分解质因数 \(\Large P=p_1^{c_1}\times p_2^{c_2}\cdots p_n^{c_n}\) ,然后分别进行计算,最后用 \(crt\) 合并出最小结果。
- 但是 \(\large p^c\) 不一定是质数,所以不能够用 \(lucas\) 计算(所以没半毛钱关系)。只有质数才一定有乘法逆元。
- 首先 \(\large\dbinom{n}{m}=\dfrac{n!}{m!(n-m)!}\) 。所以 \(\large\dbinom{n}{m}=\dfrac{\dfrac{n!}{p^x}}{\dfrac{m!}{p^y}\dfrac{(n-m)!}{p^z}}\times p^{x-y-z}\) ,其中 \(x\) , \(y\) , \(z\) 分别为 \(n!\) , \(m!\) , \((n-m)!\) 中 \(p\) 的质因子次数。
- 当其与 \(p\) 互质后,就可以求逆元了。我们只要大力求出 \(p\) 的次数,就能够计算出 \(\dbinom{n}{m}\mod p\) 的值,枚举时间复杂度为 \(O(\log{n})\) 。
- 于是我们就要着手于求 \(\LARGE\frac{n!}{p^x}\) , \(\LARGE\frac{m!}{p^y}\) , \(\LARGE\frac{(n-m)!}{p^z}\) 三个柿子的值。可以抽象为 \(\LARGE\frac{n!}{p^x}\) 。
- 对于 \(n!\) 来说,将其拆开得到 \(1\times 2\times 3\cdots(n-2)(n-1)n\) 。如果 \(n\ge p\) 则取模后结果为 \(0\) ,否则可以转化为 \((p\times 2p\times 3p\cdots)(1\times 2\times 3\times\cdots)\)
其中左边是 \(p\) 的倍数,有 \(\Large\lfloor\frac{n}{p}\rfloor\) 项,右边与 \(p\) 互质,有 \(n-\Large\lfloor\frac{n}{p}\rfloor\)(都小于 \(n\) )。 - 所以我们可以将左边的 \(p\) 提出来, 得到
\(\large p^{\lfloor\dfrac{n}{p}\rfloor}(1\times 2\times 3\cdots)(1\times 2\times 3\times\cdots)\) 等于 \(\large p^{\lfloor\frac{n}{p}\rfloor}(\lfloor\frac{n}{p}\rfloor)!\prod\limits_{\small i=1,i\not\equiv 0\pmod p}^{\small n}i\) - 将最后的一串乘法柿子提出循环部分(小于 \(n-\lfloor\frac{n}{p}\rfloor\) 的项)得出 \(\large p^{\lfloor\frac{n}{p}\rfloor}(\lfloor\frac{n}{p}\rfloor)!(\prod\limits_{\small i=1,i\not\equiv 0\pmod p}^{\small p^x}i)^{\large\lfloor\frac{n}{p^x}\rfloor}\prod\limits_{\small i=p^k\lfloor\dfrac{n}{p}\rfloor,i\not\equiv 0\pmod p}^{n}i\)
- 显然 \(\large(\prod\limits_{\small i=1,i\not\equiv 0\pmod p}^{\small p^x}i)^{\large\lfloor\frac{n}{p^x}\rfloor}\) 是循环节, \(\large\prod\limits_{\small i=p^k\lfloor\dfrac{n}{p}\rfloor,i\not\equiv 0\pmod p}^{n}i\) 是剩余部分,不能组成循环节。
- 很多地方都用 \(22!\) 举例。
\[\large
22!\equiv(1\times 2\times 4\times 5\times 7\times 8)(10\times 11\times 13\times 14\times 16\times 17)\\(19\times 20\times 22)(3\times 6\times 9\times 12\times 15\times 18\times 21)\pmod 3\\22!
\equiv(1\times 2\times 4\times 5\times 7\times 8)^2(19\times 20\times 22)\\3^7(1\times 2\times 3\times 4\times 5\times 6\times 7)\pmod 3\\22!
\equiv 3^77!(1\times 2\times 4\times 5\times 7\times 8)^2(19\times 20\times 22)\pmod 3
\]
- 如果你问为啥 \((10\times 11\times 13\times 14\times 16\times 17)\) 能直接转化成 \((1\times 2\times 4\times 5\times 7\times 8)\) ,别忘了后面的取模, \((a\times b)\mod p=(a\mod p\times b\mod p)\mod p\) ,所以 \((10\times 11\times 13\times 14\times 16\times 17)\) 就等于 \(\\((1\mod 3^2\times 10\mod 3^2)\times \\ (1\mod 3^2\times 11\mod 3^2)\times \\(1\mod 3^2\times 13\mod 3^2)\times \\(1\mod 3^2\times 14\mod 3^2)\times \\(1\mod 3^2\times 16\mod 3^2)\times \\(1\mod 3^2\times 17\mod 3^2))\mod 3^2\) , \(\\\) 等于 \((\large 1\times 2\times 4\times 5\times 7\times 8)\)
- 显然 \(\large p^{\lfloor\frac{n}{p}\rfloor}(\lfloor\frac{n}{p}\rfloor)!(\prod\limits_{\small i=1,i\not\equiv 0\pmod p}^{\small p^x}i)^{\large\lfloor\frac{n}{p^x}\rfloor}\prod\limits_{\small i=p^k\lfloor\dfrac{n}{p}\rfloor,i\not\equiv 0\pmod p}^{n}i\) 中的 \(\large p^{\lfloor\frac{n}{p}\rfloor}\) 要除掉,但是我们却不能保证 \(\large(\lfloor\frac{n}{p}\rfloor)!\) 中不包含 \(p\) 。
- 所以递归解决。定义 \(\large f(n)=\dfrac{n!}{p^x}\) ,所以 \(\large f(n)=f(\lfloor\frac{n}{p}\rfloor)(\prod\limits_{\small i=1,i\not\equiv 0\pmod p}^{\small p^x}i)^{\large\lfloor\frac{n}{p^x}\rfloor}\prod\limits_{\small i=p^k\lfloor\dfrac{n}{p}\rfloor,i\not\equiv 0\pmod p}^{n}i\) ,将可能包含因子 \(p\) 的柿子留到下一次递归计算,不含 \(p\) 的直接计算,递归结束后结果将不含因子 \(p\) ,可以用 \(\large\log_p(n)\) 的时间复杂度解决。
- 因此原式等于 \(\dfrac{f(n)}{f(m)(f(n-m))}p^{x-y-z}\pmod {p^k}\)
- 最后再求 \(p^{x-y-z}\) ,我们需要求出 \(\large p^{\lfloor\frac{n}{p}\rfloor}\) ,以及 \(\large (\lfloor\frac{n}{p}\rfloor)!\) 也不能忽视,所以定义 \(\large g(n)=\lfloor\frac{n}{p}\rfloor+g(\lfloor\frac{n}{p}\rfloor)\) 算出 \(p\) 的次数,时间复杂度也是 \(\large\log_p(n)\) 。
- 所以最后就是求出 \(\large\dfrac{f(n)}{f(m)(f(n-m))}p^{g(n)-g(m)-g(n-m)}\pmod {p^k}\) 再用 \(crt\) 合并一下就可以了。
思路
应该不是很抽象。实际上调 \(exlucas\) 才是最恶心的。- 这题显然就是求 \(\Large\sum\limits_{i=1}^{m}{\Large\dbinom{n-\sum\limits_{j=1}^{i}gift_i}{gift_i}} \mod p\) 所以用 \(exlucas\) 就可以像板子一样切掉此题……
代码
#include<bits/stdc++.h>
#define N (10000010)
#define int long long
using namespace std;
namespace IO
{
#define ll long long
const int MAX=1<<25;
char buf[MAX],*p1=buf,*p2=buf;
char obuf[MAX],*o=obuf;
#define gc()(p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
//template<typename T>
//inline T read()
inline int read()
{
int x=0;bool f=1;
char c=gc();
for(;c<48||c>57;c=gc())if(c=='-')f=0;
for(;c>=48&&c<=57;c=gc())x=(x<<3)+(x<<1)+(c^48);
return f?x:~x+1;
}
void print(ll x){if(x>9)print(x/10);*o++=(x%10)+'0';}
void pit(ll x){if(x<0)*o++='-',x=~x+1;print(x);}
void write(ll x,char end){pit(x);*o++=end;}
void flush(){fwrite(obuf,o-obuf,1,stdout);}
#undef ll
}
using IO::read;using IO::write;using IO::flush;
int n,m,t,P;
int x,y,k,ans,possible,lon;
int mod[N],a[N],gt[N],nth_mod[N];
int len,prime[700010],phi[N];//线性筛欧拉函数
short mu[N];
bitset<N>vis;
int jc[N];
long long inv[N];//乘法逆元
inline int max(int x,int y){return x>y?x:y;}
inline int min(int x,int y){return x<y?x:y;}
inline void swap(int &x,int &y){int tmp=x;x=y;y=tmp;}
int e[N],siz[N];
long long qpow(long long x,int b,int P=P)
{
long long ans=1;
for(;b;b>>=1){if(b&1)ans=(ans*x)%P;x=(x*x)%P;}
return ans;
}//O(log(b))
int gcd(int a,int b){return b?gcd(b,a%b):a;}
int exgcd(int a,int b,int &x,int &y)
{
if(!b){x=1,y=0;return a;}
int d=exgcd(b,a%b,y,x);
y-=(a/b*x);
return d;
}//O(max(a,b))
int ola(int n)
{
int ans=n;
for(int i=2;i*i<=n;++i)
{
if(n%i==0)ans=ans/i*(i-1);
for(;n%i==0;n/=i);
}
if(n>1)ans=ans/n*(n-1);
return ans;
}//O(sqrt(n))
void eular(int n)//欧拉筛
{
//memset(vis,0,sizeof(vis));
phi[1]=1;
for(int i(2);i<=n;++i)
{
if(!vis[i])
prime[++len]=i,phi[i]=(i-1);
for(int j(1);j<=len&&i*prime[j]<=n;++j)
{
vis[i*prime[j]]=1;
if(!(i%prime[j]))
{phi[i*prime[j]]=(phi[i]*prime[j]);break;}
else phi[i*prime[j]]=(phi[i]*(prime[j]-1));
}
}
}//O(n)
void mobius(int n)
{
//memset(vis,0,sizeof(vis));
mu[1]=1;
for(int i(2);i<=n;++i)
{
if(!vis[i])prime[++len]=i,mu[i]=-1;
for(int j(1);j<=len&&i*prime[j]<=n;++j)
{
vis[i*prime[j]]=1;
if(!(i%prime[j])){mu[i*prime[j]]=0;break;}
mu[i*prime[j]]=~mu[i]+1;
}
}
}//O(n)
void eular_mobius(int n)
{
//memset(vis,0,sizeof(vis));
mu[1]=phi[1]=1;
for(int i(2);i<=n;++i)
{
if(!vis[i])prime[++len]=i,phi[i]=(i-1),mu[i]=-1;
for(int j(1);j<=len&&i*prime[j]<=n;++j)
{
vis[i*prime[j]]=1;
if(!(i%prime[j]))
{
phi[i*prime[j]]=(phi[i]*prime[j]);
mu[i*prime[j]]=0;
break;
}
phi[i*prime[j]]=(phi[i]*(prime[j]-1));
mu[i*prime[j]]=~mu[i]+1;
}
}
}
void niyuan1(int n,int P=P)//乘法逆元
{
inv[1]=1;
for(int i(2);i<=n;++i)inv[i]=((P-P/i)*inv[P%i])%P;
}//O(n)
int inv_it(int a,int P=P)//O(log(a))
{
int d(exgcd(a,P,x,y));
return(x%P+P)%P;
}
int C(int n,int m,int P=P)
{
if(m>n)return 0;
int a(1),b(1);
for(int i(n-m+1);i<=n;++i)a=(a*i)%P;
for(int i(2);i<=m;++i)b=(b*i)%P;
return(a*qpow(b,P-2,P))%P;
}
int lucas(int n,int m,int P=P)
{return(!m)?1:(C(n%P,m%P,P)*lucas(n/P,m/P,P))%P;}
int excrt(int n)//扩展中国剩余定理
{
int mul(mod[1]);ans=a[1];
int x,y,c,d;
for(int i(2);i<=n;++i)
{
x=y=0;
c=(a[i]-ans%mod[i]+mod[i])%mod[i];
d=exgcd(mul,mod[i],x,y);
if(!(c%d))
ans+=(((x+mod[i])%mod[i])*(c/d)%mod[i])*mul,
mul=mul*mod[i]/gcd(mul,mod[i]),
ans%=mul;
else return -1;
}
return ans%mul;
}
int exlucas_jc(int n,int mod,int P=P)
{
if(!n)return 1;
int res(1);
for(int i(1);i<=P;++i)
if(i%mod)res=(res*i)%P;
res=qpow(res,n/P,P);
for(int i(1);i<=n%P;++i)if(i%mod)res=(res*i)%P;
return(res*(exlucas_jc(n/mod,mod,P)))%P;
}
int cal(int n,int m,int mod,int P=P)
{
int c1(exlucas_jc(n,mod,P));
int c2(exlucas_jc(m,mod,P));
int c3(exlucas_jc(n-m,mod,P));
int cnt(0);
for(int i(n);i;i/=mod)cnt+=(i/mod);
for(int i(m);i;i/=mod)cnt-=(i/mod);
for(int i(n-m);i;i/=mod)cnt-=(i/mod);
return(((qpow(mod,cnt,P)*c1)%P*inv_it(c2,P))%P*inv_it(c3,P))%P;
}
inline int crt(int x,int mod,int P)
{
return inv_it(P/mod,mod)*(P/mod)*x;
}
int exlucas(int n,int m,int now,int P)
{return(crt(cal(n,m,nth_mod[now],mod[now]),mod[now],P));}
void init()
{
P=read();
n=read(),m=read();
for(int i(1);i<=m;++i)gt[i]=read(),possible+=gt[i];
if(possible>n)puts("Impossible"),exit(0);
int PP(sqrt(P)),lsP(P);
for(int i(2);i<=PP;++i)
{
if(!(lsP%i))mod[++lon]=i,lsP/=i,nth_mod[lon]=i;
for(;!(lsP%i);lsP/=i)mod[lon]*=i;
}//分解"只因"数
if(lsP>1)mod[++lon]=lsP,nth_mod[lon]=lsP;//存在大于sqrt{n}的"只因"子
}
signed main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
init();
int sum(0),num(0);ans=1;
for(int i(1);i<=m;++i)
{
num=0;
for(int j(1);j<=lon;++j)
num=((num+exlucas(n-sum,gt[i],j,P)))%P;
ans=(ans*num)%P;
sum+=gt[i];
}
write(ans,' ');
flush();
return 0;
}