zoukankan      html  css  js  c++  java
  • I.Tower Defense

    给你p个重塔,q个轻塔,把这些塔放在n*m的图中,这些塔会相互攻击同行同列的,轻塔不能受到攻击,重塔能承受一个塔的攻击,

    问放的方法数。

    先假定n < m。

    可以先枚举放轻塔的个数为s,显然,方法数为C(n,s) * m * (m-1) * ... * (m-s+1) ,放完之后我们可以发现图其实缩小成为了一个(n-s)*(m-s)的图。

    然后放重塔,由于重塔可以承受一个塔的攻击,dp求一下方案,令dp(i,j,k) 表示i*j的图中放k个重塔的方法,通过在图的第一行进行限定条件枚举。

    可分为3个小部分:

    1.第一行不放重塔 dp(i,j,k) += dp(i-1,j,k)

    2.第一行放一个重塔,又分两种情况:

    A:同一列不放重塔 dp(i,j,k) += j*dp(i-1,j-1,k-1)

    B:同一列放重塔 dp(i,j,k) += j*(i-1)*dp(i-2,j-1,k-2)

    3.第一行放两个重塔

    dp(i,j,k) += C(j,2)*dp(i-1,j-2,k-2)

    求出dp数组之后即总方法数为segma(0,q,i) segma(0,p,j) C(n,i)*m*...*(m-i+1)*dp(n-i,m-i,j)

    由于不能不放,所以需要最后减去1.

    时间复杂度为K*200^3,K为一常数。

    #include <cmath>
    #include <cstdio>
    #include <cstdlib>
    #include <cassert>
    #include <cstring>
    #include <set>
    #include <map>
    #include <list>
    #include <queue>
    #include <string>
    #include <iostream>
    #include <algorithm>
    #include <functional>
    #include <stack>
    #include <bitset>
    using namespace std;
    typedef long long ll;
    #define INF (0x3f3f3f3f)
    #define maxn (1000005)
    #define mod 1000000007
    #define ull unsigned long long
    ll C[205][205],dp[205][205][205];
    void init(){
        for(int i = 0;i <= 200;++i) C[i][0] = 1;
        for(int i = 1;i <= 200;++i){
            for(int j = 1;j <= i;++j){
                C[i][j] = C[i-1][j] + C[i-1][j-1];
                if(C[i][j] >= mod) C[i][j] %= mod;
            }
        }
        for(int i = 0;i <= 200;++i) for(int j = 0;j <= 200;++j) dp[i][j][0] = 1;
        for(int i = 1;i <= 200;++i){
            for(int j = 1;j <= 200;++j){
                for(int k = 1;k <= 200;++k){
                    //第一行不取
                    if(i == 2 && j == 2){
                        int t = 1;
                    }
                    dp[i][j][k] += dp[i-1][j][k];
                    //第一行取一个
                    dp[i][j][k] += j * dp[i-1][j-1][k-1]%mod;//对应的列不取
                    if(dp[i][j][k] >= mod) dp[i][j][k] %= mod;
                    if(i >= 2 && k >= 2) dp[i][j][k] += j * (i-1) * dp[i-2][j-1][k-2]%mod;//对应的列取
                    if(dp[i][j][k] >= mod) dp[i][j][k] %= mod;
                    //第一行取两个
                    if(j >= 2 && k >= 2) dp[i][j][k] += C[j][2]*dp[i-1][j-2][k-2]%mod;
                    if(dp[i][j][k] >= mod) dp[i][j][k] %= mod;
                }
            }
        }
    }
    ll quickpow(ll x,ll y){
        ll ans = 1;
        while(y){
            if(y & 1){
                ans = ans * x;
                if(ans >= mod) ans %= mod;
            }
            x *= x;
            if(x >= mod) x %= mod;
            y >>= 1;
        }
        return ans;
    }
    int main()
    {
        int T;
        int n,m,p,q;
        init();
        scanf("%d",&T);
        while(T--){
            scanf("%d%d%d%d",&n,&m,&p,&q);
            if(n > m) swap(n,m);
            int li = min(q,n);
            ll s = 1,ans = 0;
            for(int i = 0;i <= li;++i){
                for(int j = 0;j <= p;++j){
                    ans = ans + C[n][i] * s % mod * dp[(n-i)][(m-i)][j] % mod;
                    if(ans >= mod) ans %= mod;
                }
                s = s * (m - i);
                if(s >= mod) s %= mod;
            }
            --ans;
            if(ans < 0) ans += mod;
            printf("%lld
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    浅谈MVC架构模式
    用JSP实现学生查询
    读cookie中文字符乱码问题
    span 换行与不换行
    SAP HANA中的Synonym使用及demo 沧海
    SAP HANA HDB序列的使用方法及技巧(SAP HANA HDB SEQUENCE ) 沧海
    SAP HANA中创建与时间相关的数据及Time Attribute View(Fiscal) 沧海
    SAP HANA中创建与时间相关的数据及Time Attribute View(Gregorian) 沧海
    SAP HANA如何在存储过程中使用自定义的table type 沧海
    SAP HANA SQL执行计划(SAP HANA SQL explain plan)(SQL 优化分析) 沧海
  • 原文地址:https://www.cnblogs.com/zhuiyicc/p/9880438.html
Copyright © 2011-2022 走看看