题解:P11838 [USACO25FEB] Printing Sequences B
考虑区间 dp,记
然后是区间 dp 的固定流程,第一层枚举区间长度,第二层枚举左右端点,第三层枚举区间内断点。
关键是如何计算一段区间内需要操作的次数。从题意可得知最优情况是将一段子区间重复多次,此时子区间内的不同元素个数会造成贡献。所以再枚举子区间长度,判断是否重复即可。转移方程为
时间复杂度
#include <bits/stdc++.h>
using namespace std;
const int N = 105;
int n,m,a[N],f[N][N],v[N];
bool check(int x,int y,int l){
for(int i=x;i<=y-l;i++) if(a[i]!=a[i+l]) return false;
return true;
}
int cal(int x,int y){
int cnt=0;
memset(v,0,sizeof v);
for(int i=x;i<=y;i++) if(!v[a[i]]) cnt++,v[a[i]]=1;
return cnt;
}
int main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int T; cin>>T;
while(T--){
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
memset(f,0x3f,sizeof f);
for(int i=1;i<=n;i++) f[i][i]=1;
for(int l=2;l<=n;l++){
for(int i=1,j=i+l-1;j<=n;i++,j++){
for(int k=i;k<j;k++) f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]);
for(int k=i;k<j;k++){
int len=k-i+1;
if(l%len!=0) continue;
if(check(i,j,len)) f[i][j]=min(f[i][j],cal(i,i+len-1));
}
}
}
// cout<<f[1][n]<<endl;
if(f[1][n]<=m) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}