zoukankan      html  css  js  c++  java
  • BZOJ1079 [SCOI2008]着色方案[组合计数DP]

    $有a_{1}个1,a_{2}个2,...,a_{n}个n(n<=15,a_{n}<=5),求排成一列相邻位不相同的方案数。$


    关于这题的教训记录:

    • 学会对于复杂的影响分开计,善于发现整体变化,用整体法(没错就是和物理那种差不多)。
    • 推dp方程时怕边界问题不好处理时可以采用向前推的方法,就如$f[x]=f[i]+...$,可以(部分)避免越界。

    我好菜啊。。除了个dp状态设计对了其他什么都没写上来qwq。基于每次插入时数字的数量都不固定,所以我可以设法将其固定下来。按顺序依次插入1,2,3,...,n即可。因为我是要统计相同不相邻方案,转移的时候肯定是插空啊,所以再设计一维表示有多少个相邻相同的($f[i][j]$),这样就好做了。然而我在这里卡主了。。因为我看数据每个数字最多5个嘛,分类大力讨论一下的事情。然而讨论到3的时候我已经崩溃掉了。觉得写法有问题,但是又不知道怎么简化。

    磕了几小时没出来QwQ,翻了题解%%%,发现还是思路狭窄了啊。每个数k个,因为要往空挡里面插,不算几张合在一起的话,分开的情况是很容易想的。而我有连续数字插入的时候,可以枚举其分组。分k组的时候,这些牌单独来看是会产生出新的$n-k$个连续位的。再看我插入时,把连续数字当做整体(就是看成一个数字),插入之前的连续位空挡相当于把他填起来了,否则无影响。所以枚举插到数字$i$,枚举之前有$j$空位连续数字,当下分为$k$组,插到之前$j$个空位里的有$l$个,之前方案$f[i][j]$,$j$个空位中选出来$l$个是$C_{j}^{l}$,剩下的非连续数字的空位还要再选$C_{sum[i-1]+1-j}^{k-l}$个,这些空位里去填$k$组,问题转为一排数字划为k组的不同方案,是经典隔板问题,有$C_{a[i]-1}^{k-1}$种。所以dp方程就出来啦。见code。可以感性认识这是不重不漏的。(??!)

    可能我组合计数还是太差了啊。几星期后到数学专题去好好补一发算了。。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<cmath>
     5 #include<algorithm>
     6 #include<queue>
     7 #define dbg(x) cerr<<#x<<" = "<<x<<endl
     8 #define dddbg(x,y,z) cerr<<#x<<" = "<<x<<"   "<<#y<<" = "<<y<<"   "<<#z<<" = "<<z<<endl
     9 using namespace std;
    10 typedef long long ll;
    11 typedef pair<int,int> pii;
    12 template<typename T>inline char MIN(T&A,T B){return A>B?A=B,1:0;}
    13 template<typename T>inline char MAX(T&A,T B){return A<B?A=B,1:0;}
    14 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
    15 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
    16 template<typename T>inline T read(T&x){
    17     x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1;
    18     while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x;
    19 }
    20 const ll P=1e9+7;
    21 int f[101][101],fac[6],C[101][101];
    22 int T,n,s[101],sum[101];
    23 inline void inc(int&A,int B){A+=B;A>=P?A-=P:0;}
    24 inline void preprocess(){
    25     C[0][0]=1;
    26     for(register int i=1;i<=76;++i){C[i][0]=1;for(register int j=1;j<=52;++j)C[i][j]=(0ll+C[i-1][j]+C[i-1][j-1])%P;}
    27 }
    28 
    29 int main(){//freopen("test.in","r",stdin);freopen("test.out","w",stdout);
    30     preprocess();read(n);
    31     for(register int i=1;i<=n;++i)read(s[i]);
    32     f[1][s[1]-1]=1;
    33     for(register int i=1;i<=n;++i)sum[i]=s[i]+sum[i-1];
    34     for(register int i=2;i<=n;++i)
    35         for(register int j=0;j<=sum[i-1]-i+1;++j)
    36             for(register int k=1;k<=s[i];++k)
    37                 for(register int l=0;l<=_min(j,k);++l)
    38                     inc(f[i][j+s[i]-k-l],f[i-1][j]*1ll*C[j][l]%P*C[sum[i-1]+1-j][k-l]%P*C[s[i]-1][k-1]%P);
    39     printf("%d
    ",f[n][0]);
    40     return 0;
    41 }

    hihocoder扑克牌:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<cmath>
     5 #include<algorithm>
     6 #include<queue>
     7 #define dbg(x) cerr<<#x<<" = "<<x<<endl
     8 #define dddbg(x,y,z) cerr<<#x<<" = "<<x<<"   "<<#y<<" = "<<y<<"   "<<#z<<" = "<<z<<endl
     9 using namespace std;
    10 typedef unsigned long long ull;
    11 typedef pair<int,int> pii;
    12 template<typename T>inline char MIN(T&A,T B){return A>B?A=B,1:0;}
    13 template<typename T>inline char MAX(T&A,T B){return A<B?A=B,1:0;}
    14 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
    15 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
    16 template<typename T>inline T read(T&x){
    17     x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1;
    18     while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x;
    19 }
    20 const int N=14;
    21 ull f[N][53],fac[5],C[54][54];
    22 int T,n,cnt[N],s[N],sum[N];
    23 char ch[4];
    24 
    25 int main(){//freopen("test.in","r",stdin);freopen("test.out","w",stdout);
    26     read(T);fac[1]=1,fac[2]=2,fac[3]=6,fac[4]=24;C[0][0]=1;
    27     for(register int i=1;i<=52;++i){
    28         C[i][0]=1;
    29         for(register int j=1;j<=52;++j)C[i][j]=C[i-1][j]+C[i-1][j-1];
    30     }
    31     for(register int o=1;o<=T;++o){
    32         read(n);memset(cnt,0,sizeof cnt);
    33         for(register int i=1;i<=n;++i){
    34             scanf("%s",ch+1);int x=ch[1]&15;
    35             if(ch[1]=='A')x=1;else if(ch[1]=='T')x=10;else if(ch[1]=='J')x=11;else if(ch[1]=='Q')x=12;else if(ch[1]=='K')x=13;
    36             ++cnt[x];
    37         }n=0;
    38         for(register int i=1;i<=13;++i)if(cnt[i])s[++n]=cnt[i],sum[n]=s[n]+sum[n-1];
    39         memset(f,0,sizeof f);f[1][s[1]-1]=1;
    40         for(register int i=2;i<=n;++i)
    41             for(register int j=0;j<=sum[i-1]-i+1;++j)
    42                 for(register int k=1;k<=s[i];++k)
    43                     for(register int l=0;l<=_min(j,k);++l)
    44                         f[i][j+s[i]-k-l]+=f[i-1][j]*C[j][l]*C[sum[i-1]+1-j][k-l]*C[s[i]-1][k-1];
    45         for(register int i=1;i<=n;++i)f[n][0]*=fac[s[i]];
    46         printf("Case #%d: %llu
    ",o,f[n][0]);
    47     }
    48     return 0;
    49 }
  • 相关阅读:
    org.springframework.beans.factory.BeanCreationException
    线程浅谈
    第五次作业
    第四次作业
    第三次作业
    第二次作业
    第一次作业
    第五次作业
    第三次作业
    第二次作业
  • 原文地址:https://www.cnblogs.com/saigyouji-yuyuko/p/10634374.html
Copyright © 2011-2022 走看看