sgu241:The United Fields of Chessboardia(DP)

(所有的图均来自于”将狼踩尽”…)
题目大意:
       题意:在如下的图中分别有 nn mm 的矩形,放车使得不相互攻击(横竖攻击)。求放 K 个车的方案数。
这里写图片描述

分析:
      我们把矩形分成上中下三段 dp ,注意有一些特殊情况,比如说

这里写图片描述

我们可以把不一般的情况通过平移变成一般情况,还不懂就研究代码去吧。

AC code:

#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <string>
#include <sstream>
#include <iostream>
#include <map>
#include <set>
#include <list>
#include <stack>
#include <queue>
#include <vector>
#define ONLINE_JUDGE
typedef long long LL;
typedef double DB;
typedef long double LD;
using namespace std;

const int MAXN = 29;
const LL MOD = 1e9;

int n, m, w, h, should;
int h1, h2, h3;
int w1, w2, w3;
struct BI
{
    LL a[10];
    BI() 
    {
        memset(a, 0, sizeof(a));
        a[0] = 1;
    }
    void init(int x) {a[1] = x;}
    void clear() 
    {
        memset(a, 0, sizeof(a));
        a[0] = 1;
    }
    void shift()
    {
        for(int i = 1; i <= a[0]; ++i)
        {
            a[i+1] += a[i]/MOD;
            a[i] %= MOD;
        }
        while(a[a[0]+1])
        {
            a[0]++;
            a[a[0]+1] += a[a[0]]/MOD;
            a[a[0]] %= MOD; 
        }
    }
    void operator += (const BI &b)
    {
        int maxsize = max(a[0], b.a[0]);
        for(int i = 1; i <= maxsize; ++i)
            a[i] += b.a[i];
        shift();
    }
    friend BI operator * (const BI &a, int k)
    {
        BI b = a;
        for(int i = 1; i <= b.a[0]; ++i)
            b.a[i] *= k;
        b.shift();
        return b;
    }
    void print()
    {
        printf("%d", (int)a[a[0]]);
        for(int i = a[0]-1; i >= 1; --i)
            printf("%09d", (int)a[i]);  
    }
    bool is_zero()
    {
        return a[0] == 1 && !a[1];  
    }
}f[2][MAXN][MAXN][MAXN], ans;

int main()
{
    #ifndef ONLINE_JUDGE
    freopen("sgu241.in", "r", stdin);
    freopen("sgu241.out", "w", stdout);
    #endif

    scanf("%d%d%d%d%d", &n, &m, &w, &h, &should);
    w = min(w, n);
    h = min(h, n);
    if(m+w <= n && m+h <= n)
    {
        h1 = h2 = h3 = n;
        w1 = w2 = w3 = n;   
    }
    else
    {
        if(m+w > n && m+h < n) h = n-m;
        if(m+w < n && m+h > n) w = n-m; 
        h1 = h, h2 = n, h3 = h1+m;
        w1 = w, w2 = n, w3 = w1+m;
    }
    f[0][0][0][0].init(1);

    for(int i = 1; i <= w1; ++i)
    {
        int now = i&1, last = now^1;
        for(int j = 0; j <= h1; ++j)
            for(int k = 0; k <= h2-h1; ++k)
                if(!f[last][j][k][0].is_zero())
                {
                    f[now][j+1][k][0] += f[last][j][k][0]*(h1-j);
                    f[now][j][k+1][0] += f[last][j][k][0]*(h2-h1-k);
                    f[now][j][k][0] += f[last][j][k][0];
                    f[last][j][k][0].clear();
                }
    }
    for(int i = w1+1; i <= w2; ++i)
    {
        int now = i&1, last = now^1;
        for(int j = 0; j <= h1; ++j)
            for(int k = 0; k <= h2-h1; ++k)
                for(int p = 0; p <= h3-h2; ++p)
                    if(!f[last][j][k][p].is_zero())
                    {
                        f[now][j+1][k][p] += f[last][j][k][p]*(h1-j);
                        f[now][j][k+1][p] += f[last][j][k][p]*(h2-h1-k);
                        f[now][j][k][p+1] += f[last][j][k][p]*(h3-h2-p);
                        f[now][j][k][p] += f[last][j][k][p];
                        f[last][j][k][p].clear();
                    }
    }
    for(int i = w2+1; i <= w3; ++i)
    {
        int now = i&1, last = now^1;
        for(int j = 0; j <= h1; ++j)
            for(int k = 0; k <= h2-h1; ++k)
                for(int p = 0; p <= h3-h2; ++p)
                    if(!f[last][j][k][p].is_zero())
                        {
                            f[now][j][k+1][p] += f[last][j][k][p]*(h2-h1-k);
                            f[now][j][k][p+1] += f[last][j][k][p]*(h3-h2-p);
                            f[now][j][k][p] += f[last][j][k][p];
                            f[last][j][k][p].clear();
                        }
    }
    for(int i = 0; i <= h1; ++i)
        for(int j = 0; j <= h2-h1; ++j)
            for(int k = 0; k <= h3-h2; ++k)
                if(i+j+k == should)
                    ans += f[w3&1][i][j][k];
    ans.print();

    #ifndef ONLINE_JUDGE
    fclose(stdin);
    fclose(stdout);
    #endif
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值