n,p,maxcost都是<=998244352
简单的方法:
设di表示有i-1个,到有i个的期望次数
E表示抽到一个五星的概率,枚举抽几次,等差×等比,可以O(1)算
然后di推出来了
∑1/i 分块打表
n<=100
不错的题目
转化为求
∑p(i步不连通的概率)
=∑1-∑p(i步连通了的概率)
=∑1-∑coef1×p(i步至少1个连通块)+coef2×p(2个)+coef3×p(3个)。。。
k是集合划分内部边的条数
怎样求出coef使得最后只剩下连通的概率
确定的集合划分贡献一些概率G(S)
而上面的式子,对于一个i个连通块的集合S,G(S)会被统计至少有j个统计S(n,j)次
而
所以配上(-1)^(i-1)*(i-1)!的系数
那么每一个连出来实际上是i个连通块的都会被消掉了
然后把∑放在一个”至少”里一起算
f[i][j][k] i个点,j个连通块,内部总共k条边方案数
O(n^5)
考虑把一维放到状态里
k:贡献复杂没法放
考虑放j
记录这个j是不必要的
-1可以转移的时候直接乘
(i-1)!可以通过除了最后一个连通块不能随便选之外胡乱排序,恰好选择(j-1)!次
用组合意义搞掉!
设f[i][k],g[i][k]分别表示j!和(j-1)!作为系数即可
f胡乱枚举连通块
g枚举和1相连的
#include<bits/stdc++.h> #define reg register int #define il inline #define numb (ch^'0') #define pii pair<int,int> #define fi first #define se second #define solid const auto& using namespace std; typedef long long ll; template<class T>il void rd(T &x){ char ch;bool fl=false; while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true); for(x=numb;isdigit(ch=getchar());x=x*10+numb); (fl==true)&&(x=-x); } template<class T>il void prt(T &a,int st,int nd){ for(reg i=st;i<=nd;++i) cout<<a[i]<<" ";puts(""); } namespace Miracle{ const int N=102; int n,mod; int f[N][N*N],g[N*N]; int C[N][N]; int ad(int x,int y){ return (x+y)>=mod?x+y-mod:x+y; } int sub(int x,int y){ return ad(x,mod-y); } void inc(int &x,int y){ x=ad(x,y); } void dec(int &x,int y){ x=sub(x,y); } int mul(int x,int y){ return (ll)x*y%mod; } int qm(int x,int y=mod-2){ int ret=1; while(y){ if(y&1) ret=mul(ret,x); x=mul(x,x); y>>=1; } return ret; } int main(){ rd(n);rd(mod); C[0][0]=1; for(reg i=1;i<=n;++i){ C[i][0]=1; for(reg j=1;j<=i;++j){ C[i][j]=ad(C[i-1][j],C[i-1][j-1]); } } f[0][0]=1; for(reg i=1;i<=n;++i){ for(reg k=1;k<=i*i;++k){ int tmp=0; for(reg sz=1;sz<=i&&sz*sz<=k;++sz){ dec(tmp,mul(C[i][sz],f[i-sz][k-sz*sz])); } f[i][k]=tmp; } } int ans=0; for(reg k=1;k<=n*n-1;++k){ for(reg sz=1;sz<=n-1&&sz*sz<=k;++sz){ inc(g[k],mul(C[n-1][sz-1],mul(mod-1,f[n-sz][k-sz*sz]))); } inc(ans,mul(g[k],mul(n*n,qm(n*n-k)))); } cout<<ans; return 0; } } signed main(){ Miracle::main(); return 0; }