zoukankan      html  css  js  c++  java
  • 【BZOJ1079】【SCOI2008】着色方案

    Time Limit: 10 Sec Memory Limit: 162 MB

    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
      
      
      

    Solution

      
      ​ 是不是还想状压啊,行不通的,状态数太多了。
      
    ​   看看还有什么是比较小的:(c_i)看起来很小。
      
    ​   仔细想一想会发现,如果两种颜料的可使用次数相同,那么它们可以归为一类颜料。
      
      ​ 从可使用次数分类入手,设状态(f[a_1][a_2][a_3][a_4][a_5][x]),表示当前已使用(i)次的颜料有(a_i)种,且下一步将要选择当前可使用(x)次的颜料,的总方案数。
      
      ​ 干脆就自顶向下使用记忆化搜索DP实现。每个状态从哪里转移就很显然了:可以挑5类颜料中的一种,那么转移的来源就是({a_1-1,a_2,a_3,a_4,a_5}),({a_1+1,a_2-1,a_3,a_4,a_5}),({a_1,a_2+1,a_3-1,a_4,a_5}),({a_1,a_2,a_3+1,a_4-1,a_5}),({a_1,a_2,a_3,a_4+1,a_5-1})
      
    ​   关键是转移的系数和递归参数。简单的讲,每类颜料(i)(a_i)种不同的选法,但这没有考虑到题目要求两两不同给的限制。
      
    ​   注意每个状态的(a_i)是相对于当前状态下的信息,而(x)则是上一层状态给你做出的限制。你枚举当前这一步将要挑哪一类颜料,递归的时候就要把这类颜料作为下一步的(x)传进去,表示你下一层自己选择的时候,如果要选我这一层选择的这类颜料,你可用的选择数必须减1,否则将会和我冲突。而上一层递归给这一层传进了(x),说明上一层递归所挑的颜料在上一层为第(x)类,那么在这一层则是第(x-1)类(没用之前即减1)。如果你枚举当前层选择了第(x-1)类颜料,可用方案数必须减1。
      
    ​   需要梳理一下思路和控制关系,实现起来并不难。
      
      
      

    #include <cstdio>
    #include <cstring>
    using namespace std;
    const int N=16,MOD=1e9+7;
    int n,a[6],c[6];
    int f[N][N][N][N][N][6];
    int dfs(int a1,int a2,int a3,int a4,int a5,int x){
    	int &F=f[a1][a2][a3][a4][a5][x];
    	if(F!=-1) return F;
    	F=0;
    	if(a1)
    		(F+=1LL*dfs(a1-1,a2,a3,a4,a5,1)*(a1-(x-1==1))%MOD)%=MOD;
    	if(a2)
    		(F+=1LL*dfs(a1+1,a2-1,a3,a4,a5,2)*(a2-(x-1==2))%MOD)%=MOD;
    	if(a3)
    		(F+=1LL*dfs(a1,a2+1,a3-1,a4,a5,3)*(a3-(x-1==3))%MOD)%=MOD;
    	if(a4)
    		(F+=1LL*dfs(a1,a2,a3+1,a4-1,a5,4)*(a4-(x-1==4))%MOD)%=MOD;
    	if(a5)
    		(F+=1LL*dfs(a1,a2,a3,a4+1,a5-1,5)*a5%MOD)%=MOD;
    	return F;
    }
    int main(){
    	freopen("input.in","r",stdin);
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++){
    		int x;
    		scanf("%d",&x);
    		c[x]++;
    	}
    	memset(f,-1,sizeof f);
    	for(int i=0;i<=5;i++)
    		f[0][0][0][0][0][i]=1;
    	printf("%d
    ",dfs(c[1],c[2],c[3],c[4],c[5],0));
    	return 0;
    }
    
  • 相关阅读:
    Kmp 加深理解 之 poj 3461
    Kmp 模板 之 hdu 1711 Number Sequence
    最大连续子序列和(经典DP) 之 hdu 1231 最大连续子序列
    数学 之 hdu 4710 Balls Rearrangement
    01背包变形 之 hdu 2126 Buy the souvenirs
    逆序数 之 hdu 1394 Minimum Inversion Number
    根据进程文件id查看所有进程信息
    N皇后问题
    17. 电话号码的字母组合
    697. 数组的度
  • 原文地址:https://www.cnblogs.com/RogerDTZ/p/8856908.html
Copyright © 2011-2022 走看看