[关闭]
@xiaoziyao 2020-05-30T15:48:25.000000Z 字数 1606 阅读 1063

[COCI 2010] ZUMA解题报告

解题报告


[COCI 2010] ZUMA解题报告:

题意:给定个珠子,每个珠子有一个颜色,每次操作可以在某一个位置插入任意一种颜色的珠子,当存在大于等于个连续的珠子为相同颜色时,这些珠子便会消失,求让所有珠子消失的最小操作数。

为了方便,在这里我们用表示

首先我们很容易看出来这是一个区间

一开始我们想设为消除从的珠子的最小操作数,然而这行不通,因为无法转移(而且数据范围也提醒你肯定不会这么简单)。

我们设一个三维数组代表在前面有个与第一颗珠子相同的珠子时,消除区间与前面的个珠子的最小操作数。

首先给初始化最大值,然后设置初始值(即区间长度为的情况):f[i][i][j]=t-j-1;

然后,开始考虑如何转移(枚举区间长度,然后枚举区间起点,即可以得到终点,最后枚举,即为在区间前的珠子数量):

  1. 在这个区间前再加上一颗珠子,然后采取的消除方式(因此我们需要采取倒推的顺序)。
  2. 如果的颜色与的颜色相同的话,可以把第颗珠子视作第颗珠子的前缀,即采取的消除方法(因为区间大小是由小至大递推的,所以肯定存在)。
  3. 寻找在这个区间内所有与颜色相同的珠子,然后将和这个位置之间所有的珠子按照消除,这样就可以视作第颗珠子的前缀,采取的消除方式。

最后记得分类讨论一下,如果的话最好单独拎出来:
1. 第一个转移方式改为
2. 第二个转移方式改为(这个地方有点难懂,其实就是因为只要有连续大于等于个相同颜色的珠子就可以消掉,因此多一颗珠子是没有关系的)。
3. 第三个转移方式的第二个消除方式改为(原因同上)。

代码:

  1. #include<stdio.h>
  2. #include<string.h>
  3. const int maxn=105,maxt=10;
  4. int i,j,k,m,n,p,t,len;
  5. int a[maxn],f[maxn][maxn][maxt];
  6. inline int min(int a,int b){
  7. return a<b? a:b;
  8. }
  9. int main(){
  10. memset(f,0x3f,sizeof(f));
  11. scanf("%d%d",&n,&t);
  12. for(i=1;i<=n;i++)
  13. scanf("%d",&a[i]);
  14. for(i=1;i<=n;i++)
  15. for(j=0;j<t;j++)
  16. f[i][i][j]=t-j-1;
  17. for(len=2;len<=n;len++)
  18. for(i=1;i+len-1<=n;i++){
  19. int j=i+len-1;
  20. f[i][j][t-1]=min(f[i][j][t-1],f[i+1][j][0]);
  21. if(a[i]==a[i+1])
  22. f[i][j][t-1]=min(f[i][j][t-1],f[i+1][j][t-1]);
  23. for(p=i+2;p<=j;p++)
  24. if(a[i]==a[p])
  25. f[i][j][t-1]=min(f[i][j][t-1],f[i+1][p-1][0]+f[p][j][t-1]);
  26. for(k=t-2;k>=0;k--){
  27. f[i][j][k]=min(f[i][j][k],f[i][j][k+1]+1);
  28. if(a[i]==a[i+1])
  29. f[i][j][k]=min(f[i][j][k],f[i+1][j][k+1]);
  30. for(p=i+2;p<=j;p++)
  31. if(a[i]==a[p])
  32. f[i][j][k]=min(f[i][j][k],f[i+1][p-1][0]+f[p][j][k+1]);
  33. }
  34. }
  35. printf("%d\n",f[1][n][0]);
  36. return 0;
  37. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注