zoukankan      html  css  js  c++  java
  • BZOJ1079 [SCOI2008]着色方案 记忆化搜索

    1079: [SCOI2008]着色方案

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 2826  Solved: 1682
    [Submit][Status][Discuss]

    Description

      有n个木块排成一行,从左到右依次编号为1~n。你有k种颜色的油漆,其中第i种颜色的油漆足够涂ci个木块。
    所有油漆刚好足够涂满所有木块,即c1+c2+...+ck=n。相邻两个木块涂相同色显得很难看,所以你希望统计任意两
    个相邻木块颜色不同的着色方案。

    Input

      第一行为一个正整数k,第二行包含k个整数c1, c2, ... , ck。

    Output

      输出一个整数,即方案总数模1,000,000,007的结果。

    Sample Input

    3
    1 2 3

    Sample Output

    10

    HINT

     100%的数据满足:1 <= k <= 15, 1 <= ci <= 5

    一开始想的组合数学,但颜色数太多没法容斥。后来想到用dp,也想到用dp[a][b][c][d][e]维护数量为1,2,3,4,5,的颜色有a,b,c,d,e种的方案数,但是不太会递推啊...
    题解:
    看黄学长的题解用的记忆化搜索,用last记录上一层用掉的是数量为last的颜色,那么该层能用的last-1的颜色就少了一个,用f[a][b][c][d][e][last]维护数量为1,2,3,4,5,的颜色有a,b,c,d,e种的方案数。
    当用掉一个数量为k的颜色时,增加的方案数为该层能用的数量为k的颜色数(即 num[k] -(last == k+1))*dfs(..,num[k-1]+1,num[k]-1,...,k)。
     
     1 /**************************************************************
     2     Problem: 1079
     3     User: mizersy
     4     Language: C++
     5     Result: Accepted
     6     Time:88 ms
     7     Memory:151292 kb
     8 ****************************************************************/
     9  
    10 #include <bits/stdc++.h>
    11 using namespace std;
    12 typedef long long ll;
    13 const ll mod = 1e9+7;
    14 ll f[20][20][20][20][20][6];
    15 ll k,w;
    16 ll num[10];
    17  
    18 ll dfs(ll a,ll b,ll c,ll d,ll e,ll last){
    19     if (f[a][b][c][d][e][last]) return f[a][b][c][d][e][last];
    20     ll ret = 0;
    21     if (a)
    22         ret = (ret + (a - (last == 2)) * dfs(a-1,b,c,d,e,1) % mod) % mod;
    23     if (b)
    24         ret = (ret + (b - (last == 3)) * dfs(a+1,b-1,c,d,e,2) % mod) % mod;
    25     if (c)
    26         ret = (ret + (c - (last == 4)) * dfs(a,b+1,c-1,d,e,3) % mod) % mod;
    27     if (d)
    28         ret = (ret + (d - (last == 5)) * dfs(a,b,c+1,d-1,e,4) % mod) % mod;
    29     if (e)
    30         ret = (ret + e * dfs(a,b,c,d+1,e-1,5) % mod) % mod;
    31     return f[a][b][c][d][e][last] = ret % mod;
    32 }
    33  
    34  
    35 int main(){
    36     scanf("%lld",&k);
    37     for (int i = 1;i <= k;++i){
    38         scanf("%lld",&w);
    39         num[w]++;
    40     }
    41     for (int i = 0;i <= 5;++i) f[0][0][0][0][0][i] = 1;
    42     printf("%lld
    ",dfs(num[1],num[2],num[3],num[4],num[5],0));
    43 }
  • 相关阅读:
    虚基类练习 动物1
    UVa 10820
    hdu1027 Ignatius and the Princess II (全排列 &amp; STL中的神器)
    在windows下安装redmine及相关问题
    批量导出表数据到CSV文件
    轻松学习Ionic (二) 为Android项目集成Crosswalk(更新官方命令行工具)
    swift第一章
    socket编程演示样例(多线程)
    谋哥:玩App怎么赚钱(三)
    Oracle database wrc运行报错ORA-15557
  • 原文地址:https://www.cnblogs.com/mizersy/p/9565955.html
Copyright © 2011-2022 走看看