从零开始的DP学习系列之贰(我的DP真的就这么烂TAT)
设DP状态的另一个技巧,考虑题目中有关答案的各种信息
然后这种和结尾有关系的$dp$可以考虑向前找结尾来转移
设$dp[i][j]$表示到第$i$天为止,有$j$天有奶牛逃跑的最小不一致记录数。转移时枚举天数和逃跑天数,然后枚举一个前一个逃跑的天数$k$,从$dp[i-1][k]$以一个$dif[k+1][i]$的代价转移过来。其中$dif[i][j]$表示从第$i$天到第$j$天中与记录不一致的数目。这样直接做是$O(n^4)$的,不过这个$dif$显然可以$O(n^2)$预处理,然后时间复杂度就降到了$O(n^3)$
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N=105; 6 int num[N],dif[N][N],dp[N][N],n; 7 int main () 8 { 9 scanf("%d",&n); 10 for(int i=1;i<=n;i++) 11 scanf("%d",&num[i]); 12 for(int i=1;i<=n;i++) 13 { 14 int tmp=0; 15 for(int j=i;j<=n;j++) 16 dif[i][j]=(tmp+=(num[j]!=j-i)); 17 } 18 memset(dp,0x3f,sizeof dp); dp[0][0]=0; 19 for(int i=1;i<=n;i++) 20 for(int j=1;j<=i;j++) 21 for(int k=0;k<i;k++) 22 dp[i][j]=min(dp[i][j],dp[k][j-1]+dif[k+1][i]); 23 for(int i=1;i<=n;i++) 24 printf("%d ",dp[n][i]); 25 return 0; 26 }