zoukankan      html  css  js  c++  java
  • BZOJ 2159: Crash 的文明世界(组合数学+第二类斯特林数+树形dp)

    传送门

    解题思路

      比较有意思的一道数学题。首先(n*k^2)的做法比较好想,就是维护一个(x^i)这种东西,然后转移的时候用二项式定理拆开转移。然后有一个比较有意思的结论就是把求(x^i)这种东西变成组合数去求,具体来说就是(n^k=sumlimits_{i=1}^kdbinom{n}{i}*S[k][i]*i!)(S)表示第二类斯特林数,第二类斯特林数可以表示为有(n)个盒子要装(m)个小球,然后在给盒子和求加上编号就可以得出上面的式子。这样的话在根据帕斯卡三角,每个组合数只会被两个组合数递推出来,所以就能(O(nk))的维护了。参考了这位大佬的博客:https://blog.csdn.net/Mys_C_K/article/details/79942486?utm_source=blogxgwz3

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
     
    using namespace std;
    const int MAXN = 50005;
    const int MOD = 10007;
    typedef long long LL;
     
    inline int rd(){
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)) {f=ch=='-'?0:1;ch=getchar();}
        while(isdigit(ch))  {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
        return f?x:-x;
    }
     
    int n,head[MAXN],cnt,to[MAXN<<1],nxt[MAXN<<1],ans[MAXN];
    int s[155][155],k,fac[MAXN],f[MAXN][155],g[MAXN][155];
     
    inline void add(int bg,int ed){
        to[++cnt]=ed,nxt[cnt]=head[bg],head[bg]=cnt;
    }
     
    inline int calc(int x,int y,int k){
        return (g[x][k]-f[y][k]-(k>0?f[y][k-1]:0)+2*MOD)%MOD;
    }
     
    void prework(){
        fac[1]=1;s[0][0]=1;
        for(int i=2;i<=k;i++) fac[i]=fac[i-1]*i%MOD;
        for(int i=1;i<=k;i++)
            for(int j=1;j<=i;j++)
                (s[i][j]=s[i-1][j-1]+j*s[i-1][j]%MOD)%=MOD;
    }
     
    void dfs1(int x,int fa){
        f[x][0]=1;int u;
        for(int i=head[x];i;i=nxt[i]){
            u=to[i];if(u==fa) continue;dfs1(u,x);f[x][0]+=f[u][0];f[x][0]%=MOD;
            for(int j=1;j<=k;j++)
                f[x][j]+=f[u][j]+f[u][j-1],f[x][j]=f[x][j]>=MOD?f[x][j]-MOD:f[x][j];
        }
    }
     
    void dfs2(int x,int fa){
        for(int i=0;i<=k;i++) g[x][i]+=f[x][i],g[x][i]%=MOD;
        int u;
        for(int i=head[x];i;i=nxt[i]){
            u=to[i];if(u==fa) continue;
            g[u][0]=g[x][0]-f[u][0];
            for(int i=1;i<=k;i++)
                g[u][i]=calc(x,u,i)+calc(x,u,i-1),g[u][i]%=MOD;
            dfs2(u,x);
        }
    }
     
    int main(){
        int now,A,B,Q,L,tmp,x,y;
        n=rd(),k=rd(),L=rd(),now=rd(),A=rd(),B=rd(),Q=rd();
        for (int i=1;i<n;i++) {
            now=(now*A+B)%Q;
            tmp=i<L?i:L;x=i-now%tmp,y=i+1; 
            add(x,y),add(y,x); 
        }
        prework();dfs1(1,0);dfs2(1,0);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=k;j++)
                ans[i]=(ans[i]+(LL)fac[j]*g[i][j]%MOD*s[k][j]%MOD)%MOD;
        for(int i=1;i<=n;i++) printf("%d
    ",ans[i]);
        return 0;
    }
    
  • 相关阅读:
    Java 中的 volatile 关键字
    Java 隐式锁
    导致并发程序出问题的根本原因是什么?
    BZOJ_2434_[Noi2011]阿狸的打字机_AC自动机+出栈入栈序+树状数组
    BZOJ_5368_[Pkusc2018]真实排名_组合数
    CF上的3道小题(2)
    BZOJ_4199_[Noi2015]品酒大会_后缀自动机
    BZOJ_4566_[Haoi2016]找相同字符_后缀自动机
    BZOJ_3172_[Tjoi2013]单词_后缀自动机
    BZOJ_3998_[TJOI2015]弦论_后缀自动机
  • 原文地址:https://www.cnblogs.com/sdfzsyq/p/10009642.html
Copyright © 2011-2022 走看看