题解: 建筑物

题目:

有R红色立方体,G绿色立方体和B蓝色立方体。每个立方体的边长是1。现在有一个N × N的木板,该板被划分成1×1个单元。现在要把所有的R+G+B个立方体都放在木板上。立方体必须放置在单元格内,单元格可以竖立放置多个立方体。

放置在板上的立方体可以被视为“建筑物”。一个“建筑物”被称为“美丽建筑物”,当且仅当:人站在南面,向北面望过去,观察建筑物时,所有可见立方体都是相同的颜色。

例如,在下图中,左侧建筑物是“美丽建筑物”,而右侧建筑物则不是。

 

问题是:给出R,G,B,N,有多少种不同的“美丽建筑物”,答案模1000000007。

题目大意:有红、蓝、绿三种颜色的正方体分别R,B,G个,放在一个N × N的平面,高度不限,使得在一个固定的方向看(在这里我们简单化为在前看),看见的所有格子颜色相同

题解:

总体思路:

     它有N行,我们可以化成小问题:第N行的放法由第N-1行推出:设第N-1行用了R1,B1,G1个红、蓝、绿方块,第N行只能用R-R1,B-B1,G-G1个红、蓝、绿方块,这时第N行的放法=第N-1行的放法*(R-R1,B-B1,G-G1个红、蓝、绿方块在一列的放法) *这时需保证这一行的放法在前看的颜色与N-1行相同

     这是近一步设数组f[i][r][b][g],i为第i行、r,b,g为到这一行(包括这一行)用的红、蓝、黄的块数(r<=R,b<=B,g<=G),g[r][b][g]:用r,b,g块红、蓝、黄正方体放在一列的放法。可转化为:f[i][r][b][g]=f[i-1][r1][b1][g1]*g[r-r1][b-b1][g-g1](r1<=r,b1<=b,g1<=g)*为保证当前行的放法在前看的颜色与前面的行相同,数组f为在前面看颜色为r的放法数,数组g为在前面看颜色为r的放法数!!!

   结果为f[N][R][B][G]+f[n][B][R][G]+f[N][G][R][B](其中数组后两维可以调换)

接下来,就是求g数组:

 可以发现:求一列的方案数和之前的想法相似,设s[i][r][b][g] :为在某一列中到第i行,为到这一行(包括这一行)用的红、蓝、黄的块数为r,b,g。

     得s[i][r][b][g]=s[i-1][r-r1][b-b1][g-g1]+(b1+g1+r1)!/b1!/r1!/g1!(r1<=r,b1<=b,g1<=g),g[r][b][g]=s[n][r][b][g]

    但是,我们发现,为这时如果b1+g1+r1大于之前的最高高度时,没法保证露在外面的部分颜色为r。所以我们要在s数组的基础上多一维分别表示:限定的最高的高度。

              同时动态转移方程便变得分多种情况考虑:分r+b+g<=h、r+b+g>h

优化:

  上面的解法时间复杂度为O(25^8),远远超过五秒时限。造成这样的原因,主要是因为枚举r,b,g,r1,b1,g1,为什么我们不妨先把它们看做一个同一个整体(即同一个颜色),先求出s数组,但在求g数组时因为我们把其看成了一种颜色,所以用组合数求出其方案数。

  这时候我们需要把之前数组s[h][n][z],h即最高高度,n即为到了第n行,z即为三总颜色块数的总数。g[G][Y]即放G个绿色的和Y个红或黄的在一列的放法。

  但是在算某个方案的实际方案数时,需知道它的最高高度H,在总共N-H个,选R-H,R即可以放在前面的方块的块数。但因为我们在s数组中不知道R,所以我们放在求g数组时求,这是发现我们s数组的漏洞:没有保证在最高高度是多少?(即H是多少?)我们在原先的数组中加多一维只有0,1来判断在s[h][n][z]的是否到达最高位。这是求g数组:g[G][Y]+=s[h][n][G+Y][1]*YHSJ[G+Y-h][G-h]*YHSJ[Y][R](YHSJ[i][j]即杨辉三角,求组合数:i个中选j个的方案数)   但是R怎么求?我们可以不考虑其,先把它等到f数组时再考虑。

  f数组的定义改为:f[i][g][y]到第i行用分别g个绿、y个红或蓝的方案数,答案=f[N][G][R+B]*YHSJ[R+B][R],这时可以发现原来R可是不需要枚举去求,可以直接在输出时*YHSJ[R+B][R]。此时,f[i][g][y]+=f[i-1][g-g1][y-y1]*f[g1][y1]。

       在最后算的时候,千万别只输出f[N][G][R+B]*YHSJ[R+B][R](这仅仅只是绿色在前面的方案数),所以输出f[N][B][R+G]*YHSJ[R+G][R]+f[N][G][R+B]*YHSJ[R+B][R]+f[N][R][G+B]*YHSJ[G+B][G]!!!

最后附上代码:

 1 #include<iostream>
 2 #include<cstring>
 3 using namespace std;
 4 long long group,rR,gG,bB,n,s[26][26][76][2],q[26][55],ans[26][26][55],mod=1000000007;
 5 long long yhsj[76][76],u;
 6 void YHSJ()
 7 {
 8     yhsj[0][0]=1;
 9     for (long long i=1;i<=75;i++)
10     {
11         for (long long j=0;j<=i;j++)
12         {
13             if (j==0)yhsj[i][j]=1;
14             else
15             {
16                 yhsj[i][j]=(yhsj[i-1][j]+yhsj[i-1][j-1])%mod;
17             }
18         }
19     }
20 } 
21 void Find(long long g,long long r,long long b,long long n)
22 {
23     long long y=r+b;
24     memset(q,0,sizeof(q));
25     memset(ans,0,sizeof(ans));
26    q[0][0]=1;
27     for (long long i=1;i<=g;i++)
28         for (long long j=0;j<=y;j++)
29           for (long long z=1;z<=i;z++)
30           {
31               q[i][j]=(q[i][j]+((s[z][n][i+j][1]*yhsj[i+j-z][i-z])%mod))%mod;    
32           }
33     ans[0][0][0]=1;
34     for (long long i=1;i<=n;i++)
35     for (long long G=0;G<=g;G++)
36     for (long long Y=0;Y<=y;Y++)
37     for (long long gg=0;gg<=G;gg++)
38     for (long long yy=0;yy<=Y;yy++)
39     {
40         ans[i][G][Y]=(ans[i][G][Y]+((ans[i-1][G-gg][Y-yy]*q[gg][yy])%mod))%mod;
41     }
42      
43     u=(u+(ans[n][g][y]*yhsj[y][b]%mod))%mod;
44 }
45 int main()
46 {
47     YHSJ();
48     for (long long maxn=1;maxn<=25;maxn++)
49     {
50         s[maxn][0][0][0]=1;
51        for (long long i=1;i<=25;i++)
52          for (long long now=0;now<=maxn;now++)
53            for (long long h=now;h<=75;h++)
54            {
55               if (now==maxn)
56               {
57                   s[maxn][i][h][1]=((s[maxn][i][h][1]+s[maxn][i-1][h-now][1]%mod)+s[maxn][i-1][h-now][0])%mod;
58               }
59               else
60               {
61                   s[maxn][i][h][1]=(s[maxn][i][h][1]+s[maxn][i-1][h-now][1])%mod;
62                   s[maxn][i][h][0]=(s[maxn][i][h][0]+s[maxn][i-1][h-now][0])%mod;
63               }
64            }
65    }
66     scanf("%lld",&group);
67     for (long long G=1;G<=group;G++)
68     {
69         u=0;
70         scanf("%lld%lld%lld%lld",&rR,&gG,&bB,&n);
71        Find(rR,gG,bB,n);
72        Find(gG,rR,bB,n);
73        Find(bB,rR,gG,n);
74        printf("%lld\n",u);
75     }
76     return 0;
77 } 

猜你喜欢

转载自www.cnblogs.com/hao-jun/p/10558278.html