求助线段树DP,不需要帮调
查看原帖
求助线段树DP,不需要帮调
234783
conprour楼主2021/10/19 11:53

整体思路理解,写出了一份正确代码如下:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ls (k<<1)
#define rs (k<<1|1)
#define mid ((l+r)>>1)
const int INF = 0x3f3f3f3f,N = 35050;
inline ll read()
{
	ll ret=0;char ch=' ',c=getchar();
	while(!(c>='0'&&c<='9')) ch=c,c=getchar();
	while(c>='0'&&c<='9') ret=(ret<<1)+(ret<<3)+c-'0',c=getchar();
	return ch=='-'?-ret:ret;
}
int n,m,a[N];
int dp[55][N],maxn[N<<2],lazy[N<<2];
int lst[N],pre[N];
void build(int k,int l,int r,const int id)
{
	lazy[k]=0;
	if(l==r) {maxn[k]=dp[id][l-1];return;}
	build(ls,l,mid,id);
	build(rs,mid+1,r,id);
	maxn[k]=max(maxn[ls],maxn[rs]);
}
inline void add(int k,int l,int r,int v)
{
	maxn[k]+=v,lazy[k]+=v;
}
inline void pushdown(int k,int l,int r)
{
	if(!lazy[k]) return;
	add(ls,l,mid,lazy[k]);
	add(rs,mid+1,r,lazy[k]);
	lazy[k]=0;
}
void modify(int k,int l,int r,int x,int y,int v)
{
	if(x<=l&&r<=y) {add(k,l,r,v);return;}
	pushdown(k,l,r);
	if(x<=mid) modify(ls,l,mid,x,y,v);
	if(y>mid) modify(rs,mid+1,r,x,y,v);
	maxn[k]=max(maxn[ls],maxn[rs]);
}
int query(int k,int l,int r,int x,int y)
{
	if(x<=l&&r<=y) return maxn[k];
	pushdown(k,l,r);
	int ret=0;
	if(x<=mid) ret=max(ret,query(ls,l,mid,x,y));
	if(y>mid) ret=max(ret,query(rs,mid+1,r,x,y));
	return ret; 
}
int main()
{
	n=read(),m=read();
	for(int i=1;i<=n;i++) 
	{
		a[i]=read();
		lst[i]=pre[a[i]];
		pre[a[i]]=i;
	}
	for(int i=1;i<=m;i++)	
	{
		build(1,1,n,i-1);
		for(int j=1;j<=n;j++)	
		{
			modify(1,1,n,lst[j]+1,j,1);
			dp[i][j]=query(1,1,n,1,j);
		}		
	}
	printf("%d\n",dp[m][n]);
	return 0;
}

但是另一份代码只有一点细节的变化,我觉得也对,但是过不去样例2,如下(区别已经标注在代码里):

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ls (k<<1)
#define rs (k<<1|1)
#define mid ((l+r)>>1)
const int INF = 0x3f3f3f3f,N = 35050;
inline ll read()
{
	ll ret=0;char ch=' ',c=getchar();
	while(!(c>='0'&&c<='9')) ch=c,c=getchar();
	while(c>='0'&&c<='9') ret=(ret<<1)+(ret<<3)+c-'0',c=getchar();
	return ch=='-'?-ret:ret;
}
int n,m,a[N];
int dp[55][N],maxn[N<<2],lazy[N<<2];
int lst[N],pre[N];
void build(int k,int l,int r,const int id)
{
	lazy[k]=0;
	if(l==r) {maxn[k]=dp[id][l];return;}//区别 1 
	build(ls,l,mid,id);
	build(rs,mid+1,r,id);
	maxn[k]=max(maxn[ls],maxn[rs]);
}
inline void add(int k,int l,int r,int v)
{
	maxn[k]+=v,lazy[k]+=v;
}
inline void pushdown(int k,int l,int r)
{
	if(!lazy[k]) return;
	add(ls,l,mid,lazy[k]);
	add(rs,mid+1,r,lazy[k]);
	lazy[k]=0;
}
void modify(int k,int l,int r,int x,int y,int v)
{
	if(x<=l&&r<=y) {add(k,l,r,v);return;}
	pushdown(k,l,r);
	if(x<=mid) modify(ls,l,mid,x,y,v);
	if(y>mid) modify(rs,mid+1,r,x,y,v);
	maxn[k]=max(maxn[ls],maxn[rs]);
}
int query(int k,int l,int r,int x,int y)
{
	if(x<=l&&r<=y) return maxn[k];
	pushdown(k,l,r);
	int ret=0;
	if(x<=mid) ret=max(ret,query(ls,l,mid,x,y));
	if(y>mid) ret=max(ret,query(rs,mid+1,r,x,y));
	return ret; 
}
int main()
{
	n=read(),m=read();
	for(int i=1;i<=n;i++) 
	{
		a[i]=read();
		lst[i]=pre[a[i]];
		pre[a[i]]=i;
	}
	for(int i=1;i<=m;i++)	
	{
		dp[i][1]=(i==1?1:0);//区别 2 
		build(1,1,n,i-1);
		for(int j=2;j<=n;j++)	//区别 3 
		{
			modify(1,1,n,lst[j],j-1,1); //区别 4 
			dp[i][j]=query(1,1,n,1,j-1); //区别 5 
			//printf("dp[%d][%d]=%d\n",i,j,dp[i][j]);
			//当前的dp[i][j]从dp[i-1][1~j-1]转移来		
		}		
	}
	printf("%d\n",dp[m][n]);
	return 0;
}

求助下面的代码为什么不对, 有做过的神帮忙解答吗?\kel

2021/10/19 11:53
加载中...