hdu 4779 Tower Defense (思维+组合数学)

Tower Defense

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Others)

Total Submission(s): 474    Accepted Submission(s): 126

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

2013 Asia Hangzhou Regional Contest

思路来源于:点击打开链接

题意:

有两种塔,重塔,轻塔。

每种塔,能攻击他所在的一行和他所在的一列, 轻塔不 能被攻击。而重塔能够被至多一个塔攻击,也就是说重塔仅仅能被重塔攻击。

在一个n*m 的矩阵中,最少放一个塔,可放多个。

问。给定p个重塔,q个轻塔。问有多少种放法。

思路:

1、 一行中有两个重塔,

2、 一列中有两个重塔

3、 在该行及在该行塔所在的列仅仅有一个塔,重塔或者轻塔。

对以上三种情况挨个处理:

1、 设有i行有两个重塔,j列有两个重塔,则一共占 i+2*j 行, j+2*i列,共用2*(i+j)个重塔,,由于一行或一列两个塔

2、 对剩余的塔,进行枚举,0<-->剩余的塔。枚举这些塔中重塔的个数进行枚举

对于1: 在行中有两个重塔 c(n,i)*c(m,2*i)*((2*i)!/2^i)   意思 是在n行中选i行,在m列中选2*i列,  对于选出来的2*i列,分成i组。须要进行全排列,可是组内不须要进行全排列。所以为(2*i)!/2^i 在列中有两个重塔,c(m-2*i,j)*c(n-i,2*j)*((2*j)!/2^j)  原理同上

对于2:设有k个塔, 在剩余的n-(i+2*j) 行  m-(2*i+j) 列中 选 k个 点 (现有的行列组合*k!),k最大为  p-2*(i+j)+q,对于k个塔,则重塔最多有b =  min (k, p-2*(i+j) ) 个,  最少有a =  max(0,k-q) 个 。k个塔,最少 a 。最多b  则为重塔的取法有(c[k][0]+c[k][1]...+c[k][b])- (c[k][0]+c[k][1]+...+c[k][a-1]);

最后将不放的情况减掉就可以,也就是减1;

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <string>
#include <map>
#include <stack>
#include <vector>
#include <set>
#include <queue>
#define maxn 405
#define MAXN 200005
#define INF 0x3f3f3f3f
#define mod 1000000007
#define eps 1e-6
const double pi=acos(-1.0);
typedef long long ll;
using namespace std;

ll n,m,ans,cnt,p,q;
ll c[maxn][maxn],sum[maxn][maxn],fac[maxn],odd[maxn];

void presolve()
{
    ll i,j;
    for(i=0;i<=200;i++) c[i][0]=sum[i][0]=1;
    for(i=1;i<=200;i++)
    {
        for(j=1;j<=i;j++)
        {
            c[i][j]=c[i-1][j]+c[i-1][j-1];
            c[i][j]%=mod;
        }
    }
    for(i=0;i<=200;i++)
    {
        for(j=1;j<=200;j++)
        {
            sum[i][j]=sum[i][j-1]+c[i][j];
            sum[i][j]%=mod;
        }
    }
    fac[0]=odd[1]=1;
    for(i=1;i<=400;i++)
    {
        fac[i]=(fac[i-1]*i)%mod;
        if(i>1&&(i&1)) odd[i]=(odd[i-2]*i)%mod;
    }
}
void solve()
{
    ll i,j,t,k;
    ans=0;
    for(i=0; i<=n; i++)
    {
        for(j=0; j<=m; j++)
        {
            if(i+2*j>n||(j+2*i)>m||2*(i+j)>p) break ;
            if(2*i-1>0) t=odd[2*i-1];
            else t=1;
            ll res=(((((c[n][i]*c[m][2*i])%mod)*t)%mod)*fac[i])%mod;
            if(2*j-1>0) t=odd[2*j-1];
            else t=1;
            res=((((res*c[m-2*i][j])%mod*c[n-i][2*j])%mod*t)%mod*fac[j])%mod;

            ll tp=p-2*(i+j),tq=q,tn=n-(i+2*j),tm=m-(j+2*i);
            for(k=0;k<=tp+tq;k++)
            {
                if(k>tn||k>tm) break ;
                ll minp=max(0LL,k-tq),maxp=min(k,tp);
                if(minp==0) t=0;
                else t=sum[k][minp-1];
                ll tmp=((((c[tn][k]*c[tm][k])%mod*fac[k])%mod)*(sum[k][maxp]-t))%mod;
                ans=(ans+tmp*res)%mod;
            }
        }
    }
    ans=(ans-1+mod)%mod;
    printf("%lld\n",ans);
}
int main()
{
    ll i,j,t;
    presolve();
    scanf("%lld",&t);
    while(t--)
    {
        scanf("%lld%lld%lld%lld",&n,&m,&p,&q);
        solve();
    }
    return 0;
}
/*
3
2 2 0 1
2 2 2 0
3 3 2 1
*/
时间: 2024-10-22 10:04:21

hdu 4779 Tower Defense (思维+组合数学)的相关文章

hdu 4779 Tower Defense 2013杭州现场赛

1 /** 2 题意: 有两种塔,重塔,轻塔.每种塔,能攻击他所在的一行和他所在的一列, 轻塔不 能被攻击,而重塔可以被至多一个塔攻击,也就是说重塔只能被重塔攻击.在一个n*m 的矩阵中,最少放一个塔,可放多个 3 问,给定p个重塔,q个轻塔,问有多少种放法.. 4 5 思路: 1. 一行中有两个重塔, 6 2. 一列中有两个重塔 7 3. 在该行及在该行塔所在的列只有一个塔,重塔或者轻塔. 8 对以上三种情况 9 挨个处理: 10 1. 设有i行有两个重塔,j列有两个重塔,则一共占 i+2*j

HDU 4939 Stupid Tower Defense(贪心+dp)

HDU Stupid Tower Defense 题目链接 题意:有一些塔,红塔能攻击经过他的,绿塔能攻击经过之后的,蓝塔能把经过之后的减速,求在1-n上放塔,求伤害最大值 思路:一开始以为直接贪心,绿塔最前,蓝塔中间,红塔最后就可以了,结果其实是错的 不过,红塔放最后是肯定的,这个很显然就不多证明了,是贪心的思想 然后就dp[i][j]表示放到i,前面有j个绿塔去状态转移即可 代码: #include <cstdio> #include <cstring> #include &l

hdu 4939 Stupid Tower Defense ( dp )

题目链接 题意:给出一条长为n个单位长度的直线,每通过一个单位长度需要t秒. 有3种塔,红塔可以在当前格子每秒造成x点伤害,绿塔可以在之后的格子每秒造成y点伤害, 蓝塔可以使通过单位长度的时间增加z秒.问如何安排3种塔的顺序使得造成的伤害最大,输出最大伤害值. 分析:比赛的时候实在是没有想出来有三种不同的 塔,每种塔的作用不同,怎么dp.看题解才知道,应该把 所有的红塔放到最后面,因为直线的长度是一定的,而红塔在前面不会增加后面的伤害,然后问题就是如何安排 绿塔和蓝塔,我这里d[i][j]代表前

2014多校第七场1005 || HDU 4939 Stupid Tower Defense (DP)

题目链接 题意 :长度n单位,从头走到尾,经过每个单位长度需要花费t秒,有三种塔: 红塔 :经过该塔所在单位时,每秒会受到x点伤害. 绿塔 : 经过该塔所在单位之后的每个单位长度时每秒都会经受y点伤害. 蓝塔 : 经过该塔所在单位之后,再走每个单位长度的时候时间会变成t+z. 思路 : 官方题解 : 1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #define LL long long

dp --- hdu 4939 : Stupid Tower Defense

Stupid Tower Defense Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 1219    Accepted Submission(s): 361 Problem Description FSF is addicted to a stupid tower defense game. The goal of tower

HDU 4939 Stupid Tower Defense(dp+贪心)

dp[i][j]表示到了第i步放了j个减速,造成的伤害.我们用贪心的策略把造成一段伤害的放在最后面,造成持续伤害的与减速放在前i个中这样得到的伤害是最高的. 所以前(i,j)中的伤害为dp[i][j] = max(dp[i-1][j]+(j*z+t)*(max(0LL, i-1-j))*y, dp[i-1][j-1]+((j-1)*z+t)*(i-j)*y); 每次造成的伤害就为:dp[i][j]+(n-i)*(j*z+t)*(x+(i-j)*y).然后取一个最大值,就是伤害的最大值了. Stu

hdu 4939 Stupid Tower Defense(DP)2014多校训练第7场

Stupid Tower Defense                                                                         Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Problem Description FSF is addicted to a stupid tower defense game. Th

HDU 4939 Stupid Tower Defense(dp)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4939 解题报告:一条长度为n的线路,路上的每个单元格可以部署三种塔来给走在这条路上的敌人造成伤害,第一种塔只给在这个塔的范围内的敌人每秒造成x点的伤害,第二种塔给已经经过过这个塔的敌人每秒造成y点伤害,第三种塔能使已经经过了这个塔的敌人的前进的速度减慢,具体效果是,原来敌人经过一个单元格的时间是t秒,经过减速后,经过每个单元格的时间是t + z,这个一个塔减速的效果,减速的效果可以叠加,同样,第二种

hdu 4939 Stupid Tower Defense (dp)

题目大意: 简单的塔防游戏,有三种塔. 一种是减速塔,只能减速它身后的敌人,使之移动速度减慢.通过一格的时间变成加z秒. 两种攻击塔,一种只能打面前,另外一种可以打身后. 思路分析: 我们默认把只能攻击面前的塔放到最后面. 状态方程: dp [i] [j]  表示放到第 i 个位置放了 j 个防御塔能达到的最大伤害. 转移方程:dp [i] [j] =max ( dp[i-1][j] + buildy ,  dp[i-1][j-1] + buildz ) buildy 表示第 i 位置建一个 攻