bzoj 2655: calc
2655: calc
Time Limit: 30 Sec Memory Limit: 512 MBSubmit: 339 Solved: 206
[Submit][Status][Discuss]
Description
一个序列a1,...,an是合法的,当且仅当:
长度为给定的n。
a1,...,an都是[1,A]中的整数。
a1,...,an互不相等。
一个序列的值定义为它里面所有数的乘积,即a1a2...an。
求所有不同合法序列的值的和。
两个序列不同当且仅当他们任意一位不一样。
输出答案对一个数mod取余的结果。
Input
一行3个数,A,n,mod。意义为上面所说的。
Output
一行结果。
Sample Input
Sample Output
HINT
数据规模和约定
0:A<=10,n<=10。
1..3:A<=1000,n<=20.
4..9:A<=10^9,n<=20
10..19:A<=10^9,n<=500。
全部:mod<=10^9,并且mod为素数,mod>A>n+1
发现可以用容斥乱搞,设f[i]为已经选了i个数的互不相等的权值和,S(n,k)为1-n的k次前缀和。
那么 f[i]=∑ f(i-j-1) * S(A,j+1) * (-1)^j * P(i-1,j) ,其中0<=j<i
相当于把下一个选的数作为基准,+一个都不同的权值和-有一个和下一个相同的权值和+有两个和下一个相同的权值和.....
接下来就是求S(n,k)了,这个玩意好像叫伯努利数,但并不是很难推。
显然的是:(n+1)^k-n^k = C(k,1)*n^(k-1) +C(k,2)*n^(k-2)+....+C(k,k)*n^0
把n从1带到n,等号左边和右边都加起来:
(n+1)^k-1=C(k,1)*S(n,k-1)+C(k,2)*S(n,k-2)+....+C(k,k)*S(n,0)
移项之后就可以通过S(n,k-1),S(n,k-2).....S(n,0)来求S(n,k)了 (需要求一下逆元)
(然而好像还有复杂度线性的求法???脑子炸了回来再学吧hhhh)
(不过跑的还蛮快的)
/************************************************************** Problem: 2655 User: JYYHH Language: C++ Result: Accepted Time:204 ms Memory:3300 kb ****************************************************************/ #include<bits/stdc++.h> #define ll long long #define maxn 505 using namespace std; ll ni[maxn],n,A,p; ll C[maxn][maxn],jc[maxn]; ll S[maxn],f[maxn]; inline void init(const ll ha){ jc[0]=C[0][0]=1; for(int i=1;i<=n+1;i++){ jc[i]=jc[i-1]*(ll)i%ha; C[i][0]=1; for(int j=1;j<=i;j++){ C[i][j]=C[i-1][j-1]+C[i-1][j]; if(C[i][j]>=ha) C[i][j]-=ha; } } ni[1]=1; for(int i=2;i<=n+1;i++) ni[i]=-ni[ha%i]*(ha/i)%ha+ha; S[0]=A; ll now=(A+1)%ha,cnt; for(int i=1;i<=n;i++){ now=now*(A+1)%ha; S[i]=1-now+ha; for(int j=i-1;j>=0;j--){ S[i]+=C[i+1][i-j+1]*S[j]; if(S[i]>=ha) S[i]-=S[i]/ha*ha; } S[i]=-S[i]; if(S[i]<0) S[i]+=ha; S[i]=S[i]*ni[i+1]%ha; } // for(int i=0;i<=n;i++) cout<<S[i]<<endl; } inline void dp(const ll ha){ f[0]=1; ll now,val; for(int i=1;i<=n;i++) for(int j=0,p=1;j<i;j++,p*=-1){ val=f[i-j-1]*S[j+1]; if(val>=ha) val-=val/ha*ha; val*=p; if(val<0) val+=ha; now=C[i-1][j]*jc[j]; if(now>=ha) now-=now/ha*ha; f[i]+=now*val; if(f[i]>=ha) f[i]-=f[i]/ha*ha; } } int main(){ scanf("%lld%lld%lld",&A,&n,&p); const ll ha=p; init(ha); dp(ha); printf("%lld\n",f[n]); return 0; }