Topcoder SRM 700 1000pts:AnyNumber(DP)

题解:
首先放满一行之后我们强制规定他可以继续放,这样总方案数是 A ( S , n ) A(\sum |S|,n) ,一个方案可能被算很多次。

处理出 f i , j f_{i,j} 表示前 i i 个第一次放满行为 j j 的概率, h i , j h_{i,j} 表示前 i i 个种选一些数放满第 j j 行的值的总和(包括第 i i 个),然后这道题就可以做了。

对于 f f 的处理只需要背包即可,对于 h h ,我们发现如果枚举每个数,枚举每个位置算贡献复杂度是 O ( n 6 ) O(n^6) 的,这时候注意到我们可以对一些数同时操作,具体的,记 g i , j , k g_{i,j,k} 表示前 i i 个数,右边放了 j j 个,长度和为 k k 的没放的数的总和, s i , j , k s_{i,j,k} 表示方案数,然后处理 g , s g,s 都是 O ( n 5 ) O(n^5) 的,我们可以利用 g g 数组算出前 i i 个种选一些数放满第 j j 行的值的总和(不一定包括第 i i 个),然后再减一下前面的就可以得到 h h 了。

#include <bits/stdc++.h>
using namespace std;

const int N=55, M=3e3+50, mod=1e9+7;
inline int add(int x,int y) {return (x+y>=mod) ? (x+y-mod) : (x+y);}
inline int dec(int x,int y) {return (x-y<0) ? (x-y+mod) : (x-y);}
inline int mul(int x,int y) {return (long long)x*y%mod;}
inline int power(int a,int b,int rs=1) {for(;b;b>>=1,a=mul(a,a)) if(b&1) rs=mul(rs,a); return rs;}
inline int cinv(int a) {return power(a,mod-2);}
inline void up(int &x,int y) {x=add(x,y);}

struct binom {
	int fac[M],ifac[M];
	binom() {
		fac[0]=1;
		for(int i=1;i<M;i++) fac[i]=mul(fac[i-1],i);
		ifac[0]=ifac[1]=1;
		for(int i=2;i<M;i++) ifac[i]=mul(mod-mod/i,ifac[mod%i]);
		for(int i=2;i<M;i++) ifac[i]=mul(ifac[i-1],ifac[i]);
	}
	inline int A(int n,int m) {
		if(n<m) return 0;
		return mul(fac[n],ifac[n-m]);
	}
	inline int C(int n,int m) {
		if(n<m) return 0;
		return mul(fac[n],mul(ifac[m],ifac[n-m]));
	}
} C;


class AnyNumber {
	int n,m,a[N],sum,val[N],f[M][N],g[N][N][M],s[N][N][M],h[N][N],tot;
	string card[N];
	int len[N],sl[N],pw[M];
	
	int pre[N][M],suf[N][M];
	inline void init_f() { // O(n^3) 
		pre[0][0]=1;
		for(int i=1;i<=m;i++)
			for(int j=0;j<=n;j++) if(pre[i-1][j])
				for(int k=0;k<a[i];++k)
					up(pre[i][j+k],mul(pre[i-1][j],mul(C.C(j+k,j),C.A(a[i],k))));
		suf[m+1][0]=1;
		for(int i=m;i;i--)
			for(int j=0;j<=n;j++) if(suf[i+1][j])
				for(int k=0;k<a[i];++k)
					up(suf[i][j+k],mul(suf[i+1][j],mul(C.C(j+k,j),C.A(a[i],k))));
		for(int i=1;i<=m;i++)
			for(int j=0;j<=n;j++) if(pre[i-1][j])
				for(int k=0;k<=n;k++) if(suf[i+1][k])
					up(f[j+k+a[i]][i],mul(mul(pre[i-1][j],suf[i+1][k]),C.C(j+k,j)));
	}
	inline void init_g() { // O(n^4)
		s[0][0][0]=1;
		for(int i=1;i<=n;i++) {
			for(int j=0;j<i;++j)
				for(int l=0;l<=sl[i-1];++l) 
					if(s[i-1][j][l]) {
						up(s[i][j][l],s[i-1][j][l]);
						up(g[i][j][l],g[i-1][j][l]);
						up(g[i][j][l],mul(s[i-1][j][l],val[i]));
						up(s[i][j+1][l+len[i]],mul(j+1,s[i-1][j][l]));
						up(g[i][j+1][l+len[i]],mul(j+1,g[i-1][j][l]));
					}
		}
	}
	inline void init_h() {
		for(int i=1;i<=n;i++)
			for(int j=1;j<=m;j++) 
        		for(int k=0;k<a[j];k++)
        			for(int l=0;l<=sl[i];++l) 
        				if(g[i][k][l]) 
        					up(h[i][j],mul(g[i][k][l],mul(C.A(i-k-1,a[j]-k-1),pw[l])));
        for(int i=n;i>=1;i--)
        	for(int j=1;j<=m;j++)
        		h[i][j]=dec(h[i][j],h[i-1][j]);
	}
    public:
    int findExpectation(vector<string> cards, vector<int> blank) {
        n=cards.size(), m=blank.size();
        for(int i=1;i<=n;i++) card[i]=cards[i-1];
        for(int i=1;i<=m;i++) a[i]=blank[i-1], sum+=a[i];
        for(int i=1;i<=n;i++) len[i]=card[i].size(), sl[i]=len[i]+sl[i-1];
        pw[0]=1; for(int i=1;i<=sl[n];i++) pw[i]=mul(pw[i-1],10);
        for(int i=1;i<=n;i++)
        	for(int j=0;j<card[i].size();++j) 
				val[i]=add(mul(val[i],10),card[i][j]-'0');
        init_f();
        init_g();
        init_h();
        int ans=0, tot=0;
        for(int i=1;i<=n;i++) // O(n^5)
        	for(int j=1;j<=m;j++) if(f[i][j]) {
        		int res=C.A(sum-i,min(n,sum)-i);
        		int cnt=mul(f[i][j],mul(C.C(i-1,a[j]-1),C.fac[a[j]]));
        		ans=add(ans,mul(h[i][j],mul(f[i][j],res)));
        		tot=add(tot,mul(cnt,res));
        	}
        return mul(ans,cinv(tot));
    }
};
发布了553 篇原创文章 · 获赞 227 · 访问量 24万+

猜你喜欢

转载自blog.csdn.net/qq_35649707/article/details/83892423