[atAGC050B]Three Coins
记$p_{i}$表示该位置是否有硬币
称使得$p_{i,i+1,i+2}$都变为1的操为对$i$的添加操作,使得$p_{i,i+1,i+2}$都变为0的操作为对$i$的删除操作
考虑一个简单的操作:若$p_{i}=1$,且$p_{i+1}=p_{i+2}=p_{i+3}=0$,可以通过执行对$i+1$的添加操作、对$i$的删除操作,使得$p_{i}$"移动"到$p_{i+3}$,我们将这个称之为对$i$的移动操作
接下来,我们证明一个$p_{i}$能通过添加和删除操作得到,当且仅当其能通过添加和移动操作得到:
由于移动操作是由添加和删除操作组合得到的,因此充分性满足
称$p_{i}=1$的来源为最后一次影响到$i$(由于最终$p_{i}=1$,必然是使其变为1)的操作位置,注意到对于来源相同的两个$p_{i}=p_{j}=1$,对其操作的时间也必然相同
考虑当执行对$i$删除操作时,对$p_{i},p_{i+1},p_{i+2}$的1的来源分类讨论,分为三种情况:
1.通过对$i$的添加操作得到,不妨将对$i$的删除操作提前到该次操作,显然无意义;
2.通过对$i-2$和$i+1$的添加操作,这也就是对$i$的移动操作;
3.通过对$i-1$和$i+2$的添加操作,这也就是对$i$和$i+1$的移动操作,等价于先对$i+1$、再对$i$的移动操作
由此,即证明删除操作都可以用添加和移动操作代替
接下来,考虑移动操作不会经过别的1,因此不会改变1的相对顺序,由此可以发现合法当且仅当:
选择第一次操作的3个1(模3不同余),将序列分为4部分(通过移动位置会发生改变),由于其他的1不会移动经过这3个1,要求每一个内部都是合法的
用$f_{i,j}$表示仅考虑区间$[i,j]$的最大值,若$i$或$j$中有一个未被选择,则$f_{i,j}=\max(f_{i+1,j},f_{i,j-1})$,否则分为两种情况:
1.左右端点是同一个,那么枚举中间的点转移即可(嵌套关系)
2.左右端点不是同一个,那么枚举两个的划分即可(并列关系)
时间复杂度为$o(n^{3})$,可以通过
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 505 4 int n,a[N],f[N][N]; 5 int main(){ 6 scanf("%d",&n); 7 for(int i=1;i<=n;i++)scanf("%d",&a[i]); 8 for(int i=n;i;i--) 9 for(int j=i+1;j<=n;j++){ 10 f[i][j]=max(f[i+1][j],f[i][j-1]); 11 for(int k=i;k<j;k++)f[i][j]=max(f[i][j],f[i][k]+f[k+1][j]); 12 for(int k=i+1;k<j;k+=3) 13 if ((j-k)%3==1)f[i][j]=max(f[i][j],f[i+1][k-1]+f[k+1][j-1]+a[i]+a[j]+a[k]); 14 } 15 printf("%d",f[1][n]); 16 }