算法:DP
难度:NOIP
题解:见代码
代码如下:
//f[i][j]表示在前i个数中经历k次出逃可以取到的最少修改数
//那么我们发现f[i][j]可以转移到的范围为f[u][j+1](i < u ≤n),然后就AC了:
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <cmath>
#include <cstdlib>
#include <queue>
#define ll long long
#define N 205
using namespace std;
int a[N];
int cnt[N][N];//Cnt[i][j]表示如果第i天出逃那么到第j天改序列需要修改的次数
int f[N][N];
int main()
{
int n;
scanf("%d",&n);
for(int i = 1;i <= n;i++)
{
scanf("%d",&a[i]);
}
for(int i = 0;i <= n;i++)//预处理cnt数组
{
int tnc=0;
for(int j = i/*注意 这里是 i */;j <= n;j++)
{
if(a[j]!=j-i) tnc++;
cnt[i][j]=tnc;
}
}
memset(f,0x3f3f3f3f,sizeof(f));
f[0][0]=0;
for(int i = 0;i <= n;i++)//dp转移
{
for(int j = 1;j <= n;j++)
{
for(int k = i+1;k <= n;k++)
{
if(f[k][j]>f[i][j-1]+cnt[i+1][k])
{
f[k][j]=f[i][j-1]+cnt[i+1][k];
}
}
}
}
for(int i = 1;i <= n;i++)
{
printf("%d\n",f[n][i]);
}
return 0 ;
}