zoukankan      html  css  js  c++  java
  • 【XSY1591】卡片游戏 DP

    题目描述

      有标有数字为(1)~(9)的卡片各(a_1,a_2cdots a_9)张,还有标有乘号的卡片(m)张。从中取出(n)张按任意顺序排列,取出两个乘号相邻和乘法在边界上的非法式子,剩下的都是合法式子。求所有合法式子的方案的值的和。两张数字相同的卡片是不同的,两张乘号也是不同的。答案模({10}^9+7)

      (nleq 1000,a_ileq {10}^8,mleq{10}^8)

    题解

      (n^underline{m}=n imes(n-1) imes(n-2) imescdots imes(n-m+1)=A(n,m))即排列数

      我们先枚举哪些位置有乘号

      现在我们考虑把(1,2,3,4)四个数字填到(\_\_ imes\_\_)这样子的算式中。假设(m=2)。把式子展开

    [egin{align} &~~~~~overline{ab} imesoverline{cd}\ &=(a imes10+b) imes(c imes10+d)\ &=a imes c imes 10 imes 10+a imes d imes 10 imes 1+b imes c imes 1 imes 10+b imes d imes 1 imes 1\ &=100ac+10ad+10bc+bd end{align} ]

      我们还有另外(23)个式子呢

    [overline{ab} imesoverline{dc}\ overline{ba} imesoverline{cd}\ overline{ba} imesoverline{dc}\ vdots ]

      另外我们发现,(ac)(ad)对答案的贡献都是相似的(因为除了乘积不同之外没有什么区别)我们考虑计算系数和出现次数

      系数会有(10 imes 10,10 imes 1,1 imes 10,1 imes 1),那么怎样计算出现次数呢?

      先钦定这两个数字放的位置(就是系数),剩下那些空位总共有两个,还剩下两个数没填,方案数就是(2^underline{2}=2)

      最后还要乘上选择乘号的方案数(2^underline{1}=2)

      于是总的贡献就是

    [(1 imes 2+1 imes 3+1 imes 4+cdots+4 imes 3) imes(100+10+10+1) imes 2 imes 2=??? ]

      现在我们来考虑更复杂的情况

      (sum)为所有数字卡片的个数和,(g_{i,j})为前(i)个数字中选出(j)个代表数字的乘积的和,(f_{i,j})为前(i)个空填了(j)个乘号的合法算式的系数和,(s_i)为这(n)个空中填入(i)个乘号的答案。

      这里只讲一下(f)的推导

    [egin{align} &~~~~~overline{ab} imes overline{cd}\ &=100ac+10ad+10bc+bd\ &=10(10ac+bc)+(10a+b)d\ end{align} ]

      那么(10ac+bc)的系数就是(overline{ab} imes c)的系数(前一个位置的系数),(10a+b)的系数就是到上一个乘号前一个位置的系数。所以我们可以枚举上一个乘号是哪个位置,然后转移

    [g_{i,j}=sum_{k=0}^{a_i}g_{i-1,k-j} imes i^k imes inom{j}{k} imes a_i^underline{k}\ f_{i,j}=f_{i-1,j} imes10+sum_{k=1}^{i}f_{k,j-1}\ s_i=g_{9,i+1} imes f_{n,i} imes {(sum-i-1)}^underline{n-i-(i+1)} imes m^underline{i} ]

      排列组合什么的可以预处理或暴力算

      时间复杂度:(O(n^2))

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cstdlib>
    #include<ctime>
    #include<utility>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pii;
    ll p=1000000007;
    int a[10];
    ll g[10][1010];
    ll f[1010][1010];
    ll s[1010][1010];
    ll aa[10][1010];
    ll pa[10][1010];
    ll cc[1010][1010];
    ll am[1010];
    ll geta(ll n,ll m)
    {
    	ll s=1;
    	int i;
    	for(i=1;i<=m;i++)
    		s=s*(n-i+1)%p;
    	return s;
    }
    int main()
    {
    //	freopen("c.in","r",stdin);
    //	freopen("c.out","w",stdout);
    	int n,m,sum=0;
    	scanf("%d%d",&n,&m);
    	int i;
    	for(i=1;i<=9;i++)
    	{
    		scanf("%d",&a[i]);
    		sum+=a[i];
    	}
    	int j,k;
    	for(i=1;i<=9;i++)
    	{
    		pa[i][0]=1;
    		aa[i][0]=1;
    		for(j=1;j<=n;j++)
    		{
    			pa[i][j]=pa[i][j-1]*i%p;
    			aa[i][j]=aa[i][j-1]*(a[i]-j+1)%p;
    		}
    	}
    	for(i=0;i<=n;i++)
    	{
    		cc[i][0]=1;
    		for(j=1;j<=i;j++)
    			cc[i][j]=(cc[i-1][j]+cc[i-1][j-1])%p;
    	}
    	g[0][0]=1;
    	for(i=1;i<=9;i++)
    		for(j=0;j<=n;j++)
    			for(k=0;k<=j&&k<=a[i];k++)
    				g[i][j]=(g[i][j]+g[i-1][j-k]*pa[i][k]%p*cc[j][k]%p*aa[i][k]%p)%p;
    	for(i=1;i<=n;i++)
    	{
    		f[i][0]=(f[i-1][0]*10+1)%p;
    		s[i][0]=(s[i-1][0]+f[i][0])%p;
    		for(j=1;j<=n;j++)
    		{
    			f[i][j]=f[i-1][j]*10%p;
    			if(i>2)
    				f[i][j]=(f[i][j]+s[i-2][j-1])%p;
    			s[i][j]=(f[i][j]+s[i-1][j])%p;
    		}
    	}
    	am[0]=1;
    	for(i=1;i<=n;i++)
    		am[i]=am[i-1]*(m-i+1)%p;
    	ll ans=0;
    	for(i=0;i<=(n-1)/2&&i<=m;i++)
    		ans=(ans+g[9][i+1]*f[n][i]%p*geta(sum-i-1,n-2*i-1)%p*am[i]%p)%p;
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    hdu5360 Hiking(水题)
    hdu5348 MZL's endless loop(欧拉回路)
    hdu5351 MZL's Border(规律题,java)
    hdu5347 MZL's chemistry(打表)
    hdu5344 MZL's xor(水题)
    hdu5338 ZZX and Permutations(贪心、线段树)
    hdu 5325 Crazy Bobo (树形dp)
    hdu5323 Solve this interesting problem(爆搜)
    hdu5322 Hope(dp)
    Lightoj1009 Back to Underworld(带权并查集)
  • 原文地址:https://www.cnblogs.com/ywwyww/p/8511369.html
Copyright © 2011-2022 走看看