• UNR #3 百鸽笼


    题目大意:在UOJ管理员群里一共有(N)个管理员,为了容纳这些管理员,vfk准备了(N+1)个鸽笼。

    为了节省空间,vfk把这些鸽笼堆了起来,共有(n)列,第i列放了(a_i)个鸽笼,满足 (sum a_i=N+1)

    每当UR结束,管理员们就会按照编号从小到大的顺序回到鸽笼里,每个管理员回来的时候,会先等概率的在所有还有剩余的鸽笼的列中随机一个列,然后住到这列剩下的鸽笼里编号最小的一个中。

    现在(N)个管理员都回笼了之后,还有一列会空出一个鸽笼。你能对于每一列,求出这一列有空鸽笼的概率吗?

    (a_i le 30, Nle 30)

    PKUWC2018猎人杀很像。

    不必要的一步,问题可以转化为无限选直到只剩一个(a_i>0)

    对于每个点,枚举一个集合(S),算出这个点在这个集合(S)所有点之前被删完的概率。显然集合外的操作我们可以忽略。

    考虑这个点被选完的时候的操作序列,这个东西可以用一个背包做出来。于是有一个(2^n * somthing)的复杂度的东西。我们再加一维表示当前的集合大小,就行了。

    瞎写一发,发现复杂度达到了(O(n^4m^2)),T了。我们把那个背包做完然后撤销就行了。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int mod=998244353;
    inline int add(int a,int b){a+=b;return a>=mod?a-mod:a;}
    inline int sub(int a,int b){a-=b;return a<0?a+mod:a;}
    inline int mul(int a,int b){return (ll)a*b%mod;}
    inline int qpow(int a,int b){int ret=1;for(;b;b>>=1,a=mul(a,a))if(b&1)ret=mul(ret,a);return ret;}
    inline int inv(int x){return qpow(x,mod-2);}
    /* math */
    const int N = 40, SZ = 910;
    int n,a[N];
    int binom[2010][2010];
    inline void preset(int n=2000){
    	binom[0][0]=1;
    	for(int i=1;i<=n;i++){
    		binom[i][0]=binom[i][i]=1;
    		for(int j=1;j<i;j++)binom[i][j]=add(binom[i-1][j-1],binom[i-1][j]);
    	}
    }
    int f[N][SZ];
    int g[N][SZ];
    
    int sum = 0;
    inline void package(int sz){
    	for(int i=1;i<=n;i++){
    		for(int j=0;j<=sum;++j){
    			g[i][j]=f[i][j];
    			for(int d=0;d<sz&&j-d>=0;d++){
    				g[i][j]=add(g[i][j],mul(f[i-1][j-d],binom[j][d]));
    			}
    		}
    	}
    	for(int i=1;i<=n;i++){
    		for(int j=0;j<=sum;++j){
    			f[i][j]=g[i][j];
    		}
    	}
    }
    
    inline void unpackage(int sz){
    	for(int i=1;i<=n;i++){
    		for(int j=0;j<=sum;++j){
    			g[i][j]=f[i][j];
    			for(int d=0;d<sz&&j-d>=0;d++){
    				g[i][j]=sub(g[i][j],mul(f[i-1][j-d],binom[j][d]));
    			}
    			f[i][j]=g[i][j];
    		}
    	}
    }
    
    
    int main()
    {
    	preset();
    	cin >> n;
    	for(int i=1;i<=n;i++)scanf("%d",&a[i]),sum+=a[i];
    	f[0][0]=1;
    	for(int i=1;i<=n;i++)package(a[i]);
    	for(int i=1;i<=n;i++){
    		unpackage(a[i]);
    		int ans=0;
    		for(int S=1;S<=n;++S){
    			for(int len=0;len<=sum;++len){
    				int totlen = len+a[i], way = mul(f[S-1][len], binom[len+a[i]-1][a[i]-1]);
    				int p=qpow(inv(S),totlen);
    				if(S&1) ans=add(ans, mul(p,way));
    				else ans=sub(ans, mul(p,way));
    			}
    		}
    		package(a[i]);
    		printf("%d ",ans);
    	}
    	puts("");
    }
    
  • 相关阅读:
    3、UML中的类图及类图之间的关系
    2、GoF的23种设计模式
    1、软件设计模式概念
    枚举
    泛型
    MySQL
    蚁群算法MATLAB解VRP问题
    蚁群算法MATLAB解TSP问题
    模拟退火解TSP问题MATLAB代码
    模拟退火学习
  • 原文地址:https://www.cnblogs.com/weiyanpeng/p/11116186.html
Copyright © 2020-2023  润新知