P16738 [GKS 2019 #F] Flattening
-
解法一
这个问题的反面问题是,在
然后你可以设一个
同时
最后答案即为
::::success[解法一代码]
#include<bits/stdc++.h>
using namespace std;
const int N=105;
int a[N],f[N][N];
int main()
{
int T;
scanf("%d",&T);
for(int t=1;t<=T;t++)
{
int n,m,maxn=0;
scanf("%d%d",&n,&m);
memset(f,0,sizeof(f));
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
{
f[i][0]=1;
for(int j=0;j<=m;j++)
{
for(int k=1;k<i;k++)
{
if(a[i]==a[k])f[i][j]=max(f[i][j],f[k][j]+1);
else if(j>=1)f[i][j]=max(f[i][j],f[k][j-1]+1);
}
maxn=max(maxn,f[i][j]);
}
}
printf("Case #%d: %d\n",t,n-maxn);
}
return 0;
}
::::
-
解法二
尝试优化成
首先注意到
对于
五个数组的转移太长了,具体参见代码。
然后注意到问题求解与
于是这样时空复杂度均为
::::success[解法二代码]
#include<bits/stdc++.h>
using namespace std;
const int N=105;
int a[N],f[N],g[N][N];
int mx[N],nx[N],mxp[N],nxp[N];
int main()
{
int T;
scanf("%d",&T);
for(int t=1;t<=T;t++)
{
int n,m,maxn=0;
scanf("%d%d",&n,&m);vector<int>Q;
for(int i=1;i<=n;i++)scanf("%d",&a[i]),Q.emplace_back(a[i]);
sort(begin(Q),end(Q)),Q.erase(unique(begin(Q),end(Q)),end(Q));
for(int i=1;i<=n;i++)a[i]=lower_bound(begin(Q),end(Q),a[i])-begin(Q);
for(int i=1;i<=n;i++)for(int j=0;j<=m;j++)g[a[i]][j]=mx[j]=mxp[j]=nx[j]=nxp[j]=0;
for(int i=1;i<=n;i++)
{
for(int j=0;j<=m;j++)f[j]=0;f[0]=1;
for(int j=0;j<=m;j++)
{
if(j>=1)
{
if(mxp[j-1]==a[i])f[j]=max(f[j],nx[j-1]+1);
else f[j]=max(f[j],mx[j-1]+1);
}
f[j]=max(f[j],g[a[i]][j]+1);
maxn=max(maxn,f[j]);
}
for(int j=0;j<=m;j++)
{
if(f[j]>mx[j])
{
if(mxp[j]!=a[i])nx[j]=mx[j],nxp[j]=mxp[j];
mx[j]=f[j],mxp[j]=a[i];
}
else if(f[j]>nx[j]&&mxp[j]!=a[i])nx[j]=f[j],nxp[j]=a[i];
if(f[j]>g[a[i]][j])g[a[i]][j]=f[j];
}
}
printf("Case #%d: %d\n",t,n-maxn);
}
return 0;
}
::::