7.10考试

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;
}

 

posted @ 2019-07-10 19:09  *Miracle*  阅读(276)  评论(1编辑  收藏  举报