HDU 4779:Tower Defense

Tower Defense

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Others)
Total Submission(s): 1025    Accepted Submission(s): 297


Problem Description
  DRD loves playing computer games, especially Tower Defense games. Tower Defense is a famous computer game with a number of variations. In general, you are to build some defense towers to guard your territory in this game. 
  However, in most Tower Defense games, your defending towers will not attack each other. You will see the shells flying through your towers and finally hit the target on your screen. DRD thinks it to be absurd, and he designed a new tower defense game.
  In DRD’s game, you have two kinds of defending tower, heavy tower and light tower. You can put the tower on a grid with N rows and M columns and each cell in the grid can hold one tower at most. Both two kinds of towers can attack the cells in the same column or the same row as it is located in, and your towers may attack each other. Moreover, light towers should not be attacked by other towers while heavy towers can be attacked by at most one other tower.
  You can put some of your towers (at least one tower) in the grid to build a tower formation satisfying the restriction above. And now, DRD wants you to calculate that how many different tower formations could be designed. Note that all the towers of the same type are considered to be identical. While the answer could be quite large, you should output the number mod (109 + 7).
 
Input
  There are multiple test cases in the input. The first line of the input file is an integer T demonstrating the number of test cases. (0< T<= 200).
  For each test case, there is only one line containing 4 integers, N, M, P and Q ,meaning that the grid has N rows and M columns, and you have P heavy towers and Q light towers. You do not have to put all the towers in the grid. (1 <= N, M <= 200, 0 <= P, Q <= 200)
 
Output
  For each test case, output the number of different formations mod (109 + 7) in a single line.
 
Sample Input
3 2 2 0 1 2 2 2 0 3 3 2 1
 
Sample Output
4 10 144
 
Source
 
Recommend
We have carefully selected several similar problems for you:  6010 6009 6008 6007 6006 

分析:

因为重塔有两种放法...其中一种是和轻塔一样的,所以可以视为轻塔...

我们枚举有i行被两个棋子所占,j列被两个棋子所占...那么总占用行数为i+2*j,列数为j+2*i,使用重塔数为(i+j)*2,这个的方案数可以用组合数学搞定:c[n][i]*c[m][i<<1]*(i<<1)!/(2^i)...这是行的算法...列的算法是一样的...c[n][i]*c[m][i<<1]就不用说了...后面的就是我们已经从m列中选出了i*2列,现在我们把这些列分配给i行,第一行选择的方案数是c[i<<1][2],第二行的方案数是c[(i<<1)-2][2],第三行的方案数是c[(i<<1)-4][2]...最后一行的方案数是c[2][2]...化简一下就是(i<<1)!/(2^i)...

然后剩下的n-(i+2*j)行和m-(j+2*i)列中选出k行k列方轻塔和重塔,应该是c[n-(i+2*j)][k]*[m-(j+2*i)][k]*(重塔方案数)...

我们求出重塔的数量范围:Min=max(0,k-q),Max=min(k,p-2*(i+j))...所以重塔的方案数应该是c[k][Max]-c[k][Min-1]...

然后乘起来加一加就好了...

代码:

WA了好久...都是细节...

首先是2^i不能直接1LL<<i,而要预处理...因为i可能等于200...

然后阶乘要预处理到400...

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
//by NeighThorn
#define int long long
using namespace std;
//眉眼如初,岁月如故 

const int maxn=400+5,Mod=1e9+7;

int n,m,p,q,cas;
long long ans,c[maxn][maxn],po[maxn],fac[maxn],sum[maxn][maxn];

inline long long power(long long x,int y){
    long long res=1;
    while(y){
        if(y&1)
            (res*=x)%=Mod;
        (x*=x)%=Mod,y>>=1;
    }   
    return res;
}

signed main(void){
//    freopen("in.txt","r",stdin);
//    freopen("out.txt","w",stdout);
    scanf("%lld",&cas);c[0][0]=sum[0][0]=1;
    for(int i=1;i<=400;i++)
        c[i][0]=1,c[i][i]=1,sum[i][0]=1;
    for(int i=1;i<=400;i++)
        for(int j=1;j<i;j++)
            c[i][j]=(c[i-1][j]+c[i-1][j-1])%Mod;
    for(int i=1;i<=400;i++)
        for(int j=1;j<=i;j++)
            sum[i][j]=(sum[i][j-1]+c[i][j])%Mod;
    fac[0]=1,po[0]=1;
    for(int i=1;i<=400;i++)
        fac[i]=fac[i-1]*i%Mod,po[i]=po[i-1]*2%Mod;
    while(cas--){
        scanf("%lld%lld%lld%lld",&n,&m,&p,&q);ans=0;
        for(int i=0;i<=n;i++)
            for(int j=0;j<=m;j++)
                if(i+2*j<=n&&j+2*i<=m&&2*(i+j)<=p){
                    long long tmp=c[n][i]*c[m][2*i]%Mod*fac[i<<1]%Mod*power(po[i],Mod-2)%Mod;  
                    (tmp*=c[m-i*2][j]*c[n-i][2*j]%Mod*fac[j<<1]%Mod*power(po[j],Mod-2)%Mod)%=Mod;
                    long long lala=0LL;
                    for(int k=0;k<=p-2*(i+j)+q;k++)
                        if(k<=n-(i+2*j)&&k<=m-(j+2*i)){
                            int Max=min(k,p-2*(i+j)),Min=max(0LL,k-q);
                            long long s;
                            if(Min==0LL)
                                s=0LL;
                            else
                                s=sum[k][Min-1];
                            (lala+=c[n-(i+2*j)][k]*c[m-(j+2*i)][k]%Mod*fac[k]%Mod*((sum[k][Max]-s+Mod)%Mod)%Mod)%=Mod;
                        }
                    (ans+=tmp*lala%Mod)%=Mod;
                }
        printf("%lld\n",(ans-1+Mod)%Mod);
    }
    return 0;  
}//Cap ou pas cap. Pas cap.

  


By NeighThorn

posted @ 2017-01-13 23:25  NeighThorn  阅读(306)  评论(0编辑  收藏  举报