zoukankan      html  css  js  c++  java
  • bzoj 1079: [SCOI2008]着色方案

    1079: [SCOI2008]着色方案

    2017-08-26


    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


    一开始想按照某鳖棋那样子暴力的,一共开15维。。(肯定不对的说,时间空间都不对);

    那看ci<=5what?数字蛮小的的说,那就可以枚举每个染料的个数。

    前五维是每一个颜料剩余i的颜色总个数;最后一维是上一次染色。

    总之很玄学。

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<algorithm>
    #define ll long long 
    using namespace std;
    const ll mod=1000000007;
    int a[10],n,t;
    ll dp[16][16][16][16][16][6];
    bool rem[16][16][16][16][16][6];
    ll F(int a,int b,int c,int d,int e,int k){
        if(a+b+c+d+e==0){
        rem[a][b][c][d][e][k]=dp[a][b][c][d][e][k]=1;return 1;}
        if(dp[a][b][c][d][e][k])return dp[a][b][c][d][e][k];
        ll t=0;
        if(a)t+=(a-(k==2))*F(a-1,b,c,d,e,1);
        if(b)t+=(b-(k==3))*F(a+1,b-1,c,d,e,2);
        if(c)t+=(c-(k==4))*F(a,b+1,c-1,d,e,3);
        if(d)t+=(d-(k==5))*F(a,b,c+1,d-1,e,4);
        if(e)t+=(e)*F(a,b,c,d+1,e-1,5);
        rem[a][b][c][d][e][k]=1;dp[a][b][c][d][e][k]=t%mod;
        return t%mod;
    }
    int main(){
        cin>>n;
        for(int i=1;i<=n;i++){cin>>t;a[t]++;}
        cout<<F(a[1],a[2],a[3],a[4],a[5],0)%mod;
        return 0;
    }

    by:s_a_b_e_r


    最近s同学学会了读入优化

    还没看题先开始写读入优化

    于是看到数据范围之后……ww

    一开始各种瞎想……组合数?容斥?

    想不出来.jpg

    后来看了题解,记忆化搜

    因为如果两种油漆剩余使用次数一样的话,可以看做等效的说

    f[a][b][c][d][e][l]表示剩余1次的油漆有a种……剩余5次的油漆有e种,l表示上次涂的颜色

    如果上一次用的是l油漆,这一次就不能再涂l油漆

    于是就有了这个神奇的转移方程

    #include<iostream>
    #include<cstdio>
    using namespace std;
    const int M=1000000007;
    int k,c[10];
    long long f[16][16][16][16][16][6];
    long long dp(int a,int b,int c,int d,int e,int l)
    {
         if(a+b+c+d+e==0)return 1;
         if(f[a][b][c][d][e][l])return f[a][b][c][d][e][l];
         long long t=0;
         if(a)t+=(a-(l==2))*dp(a-1,b,c,d,e,1);
         if(b)t+=(b-(l==3))*dp(a+1,b-1,c,d,e,2);
         if(c)t+=(c-(l==4))*dp(a,b+1,c-1,d,e,3);
         if(d)t+=(d-(l==5))*dp(a,b,c+1,d-1,e,4);
         if(e)t+=e*dp(a,b,c,d+1,e-1,5);
         f[a][b][c][d][e][l]=t%M;
         return f[a][b][c][d][e][l];
    }
    int main()
    {
        cin>>k;
        int x;
        for(int i=1;i<=k;++i){cin>>x;++c[x];}
        long long ans=dp(c[1],c[2],c[3],c[4],c[5],0)%M;
        cout<<ans<<endl;
        return 0;
    }
    1079(wypx)

    s:=wow=,点兔的音乐太好了,害得我没法专心打oi模拟赛了

    w:快把你耳机摘下来……等等我先把我耳机摘下来x

  • 相关阅读:
    小tips: HTTP 请求过程示例图及名称解释
    小tips:使用vuecli2脚手架配置vant自定义主题
    axios使用备忘录
    知乎问题:为什么很多web项目还是使用 px,而不是 rem?
    小tips:HTML5的ruby标签实现给汉字加拼音、details标签实现折叠面板、原生进度条progress和度量meter
    ES6之常用开发知识点:入门(一)
    GitBook相关使用以及配置笔记
    小tips:使用vue-cli脚手架搭建项目,关于eslint语法检测配置
    小tips:JS/CSS实现字符串单词首字母大写
    vue动态子组件的实现方式
  • 原文地址:https://www.cnblogs.com/ck666/p/7436167.html
Copyright © 2011-2022 走看看