NC20265 [SCOI2008]着色方案(记忆化搜索)

题目链接

题意:
有 n 个 木 块 有n个木块 n
k 种 油 漆 , 每 种 c i 个 k种油漆,每种c_i个 kci
c 1 + c 2 + … … + c k = n c_1+c_2+……+c_k=n c1+c2++ck=n
相 邻 两 个 木 块 不 能 涂 相 同 颜 色 相邻两个木块不能涂相同颜色
求 方 案 数 求方案数
题解:
k < = 15 , c i < = 5 k<=15,c_i<=5 k<=15,ci<=5
数 据 很 小 , 所 以 可 以 直 接 考 虑 暴 力 算 法 数据很小,所以可以直接考虑暴力算法
但 是 枚 举 每 种 颜 色 的 话 , 颜 色 种 类 数 是 15 , 仍 然 会 超 时 但是枚举每种颜色的话,颜色种类数是15,仍然会超时 15

但 是 c i 很 小 , 可 以 从 这 里 进 行 操 作 但是c_i很小,可以从这里进行操作 ci
可 以 每 次 选 择 固 定 的 c i 进 行 使 用 可以每次选择固定的c_i进行使用 ci使
记 忆 化 搜 索 5 种 个 数 的 颜 色 记忆化搜索5种个数的颜色 5
d p [ a ] [ b ] [ c ] [ d ] [ e ] [ l a ] dp[a][b][c][d][e][la] dp[a][b][c][d][e][la]
表 示 现 在 有 a 种 1 个 , b 种 2 个 , e 种 5 个 颜 色 的 油 漆 , 并 且 上 一 个 用 了 l a 个 颜 色 的 表示现在有a种1个,b种2个,e种5个颜色的油漆,并且上一个用了la个颜色的 a1b2e5la
对 于 每 次 使 用 , 会 使 得 当 前 个 数 颜 色 的 油 漆 减 少 对于每次使用,会使得当前个数颜色的油漆减少 使使
使 得 当 前 个 数 减 一 的 颜 色 油 漆 增 加 使得当前个数减一的颜色油漆增加 使
所 以 如 果 上 次 使 用 的 油 漆 颜 色 是 这 次 使 用 颜 色 个 数 加 一 所以如果上次使用的油漆颜色是这次使用颜色个数加一 使使
就 需 要 减 去 一 个 , 就 是 上 次 使 用 的 颜 色 , 使 其 不 会 相 邻 就需要减去一个,就是上次使用的颜色,使其不会相邻 使使
然 后 直 接 搜 索 并 且 维 护 值 即 可 然后直接搜索并且维护值即可

AC代码

/*
    Author : zzugzx
    Lang : C++
    Blog : blog.youkuaiyun.com/qq_43756519
*/
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(), (x).end()
#define endl '\n'
#define SZ(x) (int)x.size()
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int mod = 1e9 + 7;
const int MOD = 998244353;
const double eps = 1e-10;
const double pi = acos(-1.0);
const int maxn = 1e6 + 10;
//const int N = 1e3 + 10;
const ll inf = 0x3f3f3f3f;
const int dir[][2]={{0, 1}, {1, 0}, {0, -1}, {-1, 0}, {1, 1}, {1, -1}, {-1, 1}, {-1, -1}};

ll dp[16][16][16][16][16][6], t[6];
ll dfs(int a, int b, int c, int d, int e, int la) {
    if (dp[a][b][c][d][e][la] != -1)
        return dp[a][b][c][d][e][la];
    if (a + b + c + d + e == 0)
        return 1;
    ll ans = 0;
    if (a) ans = (ans + (a - (la == 2)) * dfs(a - 1, b, c, d, e, 1)) % mod;
    if (b) ans = (ans + (b - (la == 3)) * dfs(a + 1, b - 1, c, d, e, 2)) % mod;
    if (c) ans = (ans + (c - (la == 4)) * dfs(a, b + 1, c - 1, d, e, 3)) % mod;
    if (d) ans = (ans + (d - (la == 5)) * dfs(a, b, c + 1, d - 1, e, 4)) % mod;
    if (e) ans = (ans + e * dfs(a, b, c, d + 1, e - 1, 5)) % mod;
    return dp[a][b][c][d][e][la] = ans;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
//  freopen("in.txt", "r", stdin);
//  freopen("out.txt", "w", stdout);
    int k;
    cin >> k;
    for (int i = 1; i <= k; i++){
        int x;
        cin >> x;
        t[x]++;
    }
    memset(dp, -1, sizeof dp);
    cout << dfs(t[1], t[2], t[3], t[4], t[5], 0);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值