[关闭]
@ysner 2018-07-25T17:26:35.000000Z 字数 2664 阅读 1939

[SCOI2008]着色方案

DP


题面

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

解析

算法

直接暴力记搜,状态表示 在各油漆剩余量如此,上一次涂第种油漆时 有多少种方案。
空间复杂度开得下,时间复杂度同。

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstdlib>
  4. #include<cstring>
  5. #include<cmath>
  6. #include<algorithm>
  7. #define re register
  8. #define il inline
  9. #define ll long long
  10. #define max(a,b) ((a)>(b)?(a):(b))
  11. #define min(a,b) ((a)<(b)?(a):(b))
  12. #define fp(i,a,b) for(re int i=a;i<=b;i++)
  13. #define fq(i,a,b) for(re int i=a;i>=b;i--)
  14. using namespace std;
  15. const int mod=1e9+7;
  16. ll dp[20][5][5][5][5][5][5],k,a[20],tot;
  17. il ll gi()
  18. {
  19. re ll x=0,t=1;
  20. re char ch=getchar();
  21. while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
  22. if(ch=='-') t=-1,ch=getchar();
  23. while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
  24. return x*t;
  25. }
  26. il ll dfs(re int x,re int a1,re int a2,re int a3,re int a4,re int a5,re int las)
  27. {
  28. re ll sum=0;
  29. if(!x) return 1;
  30. if(dp[x][a1][a2][a3][a4][a5][las]) return dp[x][a1][a2][a3][a4][a5][las];
  31. if(a1&&las!=1) sum+=dfs(x-1,a1-1,a2,a3,a4,a5,1);
  32. if(a2&&las!=2) sum+=dfs(x-1,a1,a2-1,a3,a4,a5,2);
  33. if(a3&&las!=3) sum+=dfs(x-1,a1,a2,a3-1,a4,a5,3);
  34. if(a4&&las!=4) sum+=dfs(x-1,a1,a2,a3,a4-1,a5,4);
  35. if(a5&&las!=5) sum+=dfs(x-1,a1,a2,a3,a4,a5-1,5);
  36. sum%=mod;
  37. return dp[x][a1][a2][a3][a4][a5][las]=sum;
  38. }
  39. int main()
  40. {
  41. k=gi();
  42. fp(i,1,k) a[i]=gi(),tot+=a[i];
  43. printf("%lld\n",dfs(tot,a[1],a[2],a[3],a[4],a[5],0));
  44. return 0;
  45. }

算法

我竟然完全没注意到
可以发现,油漆量相同的油漆,对答案的贡献本质是相同的。
所以状态改成:表示 各油漆剩余量的油漆种数如此,上一次涂第种油漆时 有多少种方案即可。

  1. // luogu-judger-enable-o2
  2. #include<iostream>
  3. #include<cstdio>
  4. #include<cstdlib>
  5. #include<cstring>
  6. #include<cmath>
  7. #include<algorithm>
  8. #define re register
  9. #define il inline
  10. #define ll long long
  11. #define max(a,b) ((a)>(b)?(a):(b))
  12. #define min(a,b) ((a)<(b)?(a):(b))
  13. #define fp(i,a,b) for(re int i=a;i<=b;i++)
  14. #define fq(i,a,b) for(re int i=a;i>=b;i--)
  15. using namespace std;
  16. const int mod=1e9+7;
  17. ll dp[16][16][16][16][16][6],k,tong[20];
  18. il ll gi()
  19. {
  20. re ll x=0,t=1;
  21. re char ch=getchar();
  22. while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
  23. if(ch=='-') t=-1,ch=getchar();
  24. while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
  25. return x*t;
  26. }
  27. il ll dfs(re int a1,re int a2,re int a3,re int a4,re int a5,re int las)
  28. {
  29. re ll sum=0;
  30. if(a1+a2+a3+a4+a5==0) return 1;
  31. if(dp[a1][a2][a3][a4][a5][las]!=-1) return dp[a1][a2][a3][a4][a5][las];
  32. if(a1) sum+=(a1-(las==2))*dfs(a1-1,a2,a3,a4,a5,1);//上次涂的油漆油漆量减了1
  33. if(a2) sum+=(a2-(las==3))*dfs(a1+1,a2-1,a3,a4,a5,2);
  34. if(a3) sum+=(a3-(las==4))*dfs(a1,a2+1,a3-1,a4,a5,3);
  35. if(a4) sum+=(a4-(las==5))*dfs(a1,a2,a3+1,a4-1,a5,4);
  36. if(a5) sum+=a5*dfs(a1,a2,a3,a4+1,a5-1,5);
  37. sum%=mod;
  38. return dp[a1][a2][a3][a4][a5][las]=sum;
  39. }
  40. int main()
  41. {
  42. k=gi();
  43. fp(i,1,k) tong[gi()]++;
  44. memset(dp,-1,sizeof(dp));
  45. printf("%lld\n",dfs(tong[1],tong[2],tong[3],tong[4],tong[5],0));
  46. return 0;
  47. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注