专栏文章

题解:P11838 [USACO25FEB] Printing Sequences B

P11838题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@miprfsb5
此快照首次捕获于
2025/12/03 16:43
3 个月前
此快照最后确认于
2025/12/03 16:43
3 个月前
查看原文
考虑区间 dp,记 fi,jf_{i,j} 为从 iijj 的区间内最少要进行几次操作。
然后是区间 dp 的固定流程,第一层枚举区间长度,第二层枚举左右端点,第三层枚举区间内断点。
关键是如何计算一段区间内需要操作的次数。从题意可得知最优情况是将一段子区间重复多次,此时子区间内的不同元素个数会造成贡献。所以再枚举子区间长度,判断是否重复即可。转移方程为 fi,j=min(fi,j,cal(i,i+len1))f_{i,j} = \min(f_{i,j},cal(i,i+len-1))。其中 lenlen 是子区间长度,calcal 函数用来计算贡献。
时间复杂度 O(n4)O(n^4)
CPP
#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;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...