您的位置:首页 > 其它

[BestCoder Round #25 1002]Harry And Magic Box 解题报告

2015-01-03 21:55 477 查看



Harry And Magic Box

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 0 Accepted Submission(s): 0

Problem Description

One day, Harry got a magical box. The box is made of n*m grids. There are sparking jewel in some grids. But the top and bottom of the box is locked by amazing magic, so Harry can’t see the inside from the top or bottom. However, four sides of the box are transparent, so Harry can see the inside from the four sides. Seeing from the left of the box, Harry finds each row is shining(it means each row has at least one jewel). And seeing from the front of the box, each column is shining(it means each column has at least one jewel). Harry wants to know how many kinds of jewel’s distribution are there in the box.And the answer may be too large, you should output the answer mod 1000000007.




Input

There are several test cases.
For each test case,there are two integers n and m indicating the size of the box. 0≤n,m≤50.




Output

For each test case, just output one line that contains an integer indicating the answer.




Sample Input

1 1
2 2
2 3




Sample Output

1
7
25
HintThere are 7 possible arrangements for the second test case.
They are:
11
11

11
10

11
01

10
11

01
11

01
10

10
01

Assume that a grids is '1' when it contains a jewel otherwise not.


先给一下题解:

1002 Harry And Magic Box
dp题,我们一行一行的考虑。dp[i][j],表示前i行,都满足了每一行至少有一个宝石的条件,而只有j列满足了有宝石的条件的情况有多少种。枚举第i+1行放的宝石数k,这k个当中有t个是放在没有宝石的列上的,那么我们可以得到转移方程:
dp[i+1][j+t]+=dp[i][j]*c[m-j][t]*c[j][k-t],其中c[x][y],意为在x个不同元素中无序地选出y个元素的所有组合的个数。

题解有其闪光的地方:

①将比较奇怪与陌生的二维状态转换为更熟悉的一维递推方式。

②当发现直接按题意中所给状态设计方程遇到困难时,试图转化状态。

但是呢。。显然题解的时间复杂度为

,T为数据组数;而如果T较大时,这显然是不好办的。。当然,既然是题解,数据显然要弱到足够让题解过。

我不是这么做的,我使用了不同的DP方式:

设f[i][j]为题目所需ans。那么如果我们能预先处理出所有的f(i,j),就可以做到离线的O(1)询问了。



当然对于这个DP方程来说,如果在线是跟题解的时间复杂度类似的



但它可以做到

的预处理,使得时间复杂度达到



下面我想来解释一下DP方程:③使用正难则反的思想;尤其是在排列组合中,这种思想尤为重要。

考虑不合法的情况:

①有k行没有发光,其余i-k行j列均每列每行都有光;我们可以通过排列组合和之前的状态推得它。

②如果有t列没有发光,而其余同上,那么也是类似的。

③但是,如果i行j列都没有发光呢?那只会有1种情况。

④可是。。考虑如上几种情况,我们却发现我们没有过样例。这是怎么回事呢?原来,还存在有k行t列没有光的情况!

至此,我们已经通过简单地思路完美地解决DP方程了,此时k与t的取值范围也是显而易见了:k∈(0,i),t∈(0,j)

而我们只需要在所有的情况中减去上述不合法的情况即可,因为每一个格子均有0/1两种状态,所以总的情况有

种。

也许你会觉得这道题到此结束了。

但是。。

没有!绝对没有!

④无论是简单的题还是难题,一定要看清变量范围!坑点在这里,亮点也在这里!

本题中,n和m的取值范围——包括0!

那么我们就必须来考虑当n*m=0时会发生什么了。考虑题中的描述,Harry看到每行每列都有珠宝,那么假若n*m=0,他还能在每行每列看到珠宝么?所以,显而易见,f(i,j)=0,当i=0或j=0.

综上,不得不说,这是一道非常好的DP+排列组合的题,比赛的时候我花了1h的时间才做出来,这体现了我能力的不足;而且,应该说于我还是获益匪浅的。包括对于审题的重视、对于正难则反思想的领会、对于DP状态的设计、对于二维向一维的化规,都给以我深刻的启发。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#include<iostream>
#define P 1000000007
int main(){
    
    int i,j,k,t,ni[2501],f[51][51],n,m;
    long long C[51][51]={0};
    
    ni[0]=1;
    for(i=1;i<2501;++i)ni[i]=(ni[i-1]<<1)%P;
    
    for(i=0;i<51;++i)C[i][0]=1;
    for(i=1;i<51;++i)
        for(j=1;j<51;++j)
            C[i][j]=(C[i-1][j]+C[i-1][j-1])%P;
    
    for(i=1;i<51;++i)
        for(j=1;j<51;++j){
            f[i][j]=ni[i*j]-1;
            for(k=1;k<i;++k)
                f[i][j]=(f[i][j]-f[i-k][j]*C[i][k]%P)%P;
            for(t=1;t<j;++t)
                f[i][j]=(f[i][j]-f[i][j-t]*C[j][t]%P)%P;
            for(k=1;k<i;++k)
                for(t=1;t<j;++t)
                    f[i][j]=(f[i][j]-f[i-k][j-t]*C[i][k]%P*C[j][t])%P;
            f[i][j]=(f[i][j]+P)%P;
        }
    while(~scanf("%d%d",&n,&m))
        printf("%d\n",f
[m]);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: