HDU6249

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/liufengwei1/article/details/83176821

好久没做过一道像样的区间DP了,做出来得慢了点,一开始还用个堆维护最优值然后超时了,菜哭.jpg

f[i][j]表示覆盖i段邮集,1到j号颜色最多能覆盖多少个,那么能转移到f[i][j]的必定是[x,y]包含j颜色的邮集,用一个单调队列来维护这些邮集能转移到f[i][j]的最优值。但是入队的时候是按照x的位置来入队,队首出队的时候表示已经对j这个位置没有影响了,则是根据y来队首出队,我们贪心地考虑到,如果一个区间被另外一个区间包含,那么它肯定不是最优的,把他标记为不选,那么单调队列入队是按照x从左到右的,队首出队的y也是从左到右的,那么就满足单调队列的性质了(不满足的话就不能用要用堆了)。

#include<bits/stdc++.h>
#define maxl 2010

using namespace std;

int n,cnt,m,k,cas,ans,top;
int f[maxl][maxl];
struct lne
{
  int l,r;
  bool operator <(const lne &b) const
  {
    if(l==b.l)
      return r>b.r;
    else
      return l<b.l;
  }
}a[maxl];
int head,tail;
struct node
{
  int val,r;
}q[maxl];
bool in[maxl];

inline void prework()
{
  scanf("%d%d%d",&n,&m,&k);
  for(int i=1;i<=k;i++)
    for(int j=1;j<=n;j++)
      f[i][j]=0;
  for(int i=1;i<=m;i++)
    scanf("%d%d",&a[i].l,&a[i].r),in[i]=true;
  sort(a+1,a+1+m);
  int last=1;cnt=1;
  for(int i=2;i<=m;i++)
    if(a[i].r<=a[last].r)
      in[i]=false;
    else
      last=i,cnt++;
  k=min(k,cnt);
}

inline void mainwork()
{
  ans=0;
  int id;
  for(int i=1;i<=k;i++)
    {
      head=1;tail=0;id=1;
      for(int j=1;j<=n;j++)
	{
	  while(a[id].l<=j && id<=m)
	    {
	      if(in[id])
		{
		  int l=a[id].l,r=a[id].r,tmp=f[i-1][l-1]-l+1;
		  while(head<=tail && (tmp>q[tail].val || (tmp==q[tail].val && r>=q[tail].r)))
		    tail--;
		  q[++tail]=node{tmp,r};
		}
	      id++;
	    }
	  while(head<=tail && q[head].r<j)
	    head++;
	  f[i][j]=max(f[i][j-1],f[i-1][j]);
	  if(head<=tail)
	    f[i][j]=max(f[i][j],q[head].val+j);
	}
    }
}

inline void print()
{
  ans=0;
  printf("Case #%d: %d\n",cas,f[k][n]);
}

int main()
{
  int t;
  scanf("%d",&t);
  for(cas=1;cas<=t;cas++)
    {
      prework();
      mainwork();
      print();
    }
  return 0;
}

后来发现:

因为覆盖是连续的,那么覆盖得肯定越远越好,我们用t[j]表示所有覆盖过j位置的邮集y最远的地方是哪里,那么直接由f[i-1][j-1]转移到f[i][t[j]]就行了,然后f[i][j]=max(f[i][j],f[i-1][j],f[i][j-1])

#include<bits/stdc++.h>
#define maxl 2010

using namespace std;

int n,m,k,cas;
int t[maxl];
int f[maxl][maxl];

inline void prework()
{
	scanf("%d%d%d",&n,&m,&k);
	for(int i=1;i<=k;i++)
		for(int j=1;j<=n;j++)
			f[i][j]=0,t[j]=0;
	int x,y;
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&x,&y);
		for(int j=x;j<=y;j++)
			t[j]=max(t[j],y);
	}
}

inline void mainwork()
{
	for(int i=1;i<=k;i++)
	{
		for(int j=1;j<=n;j++)
		{
			f[i][j]=max(f[i][j],max(f[i-1][j],f[i][j-1]));
			if(t[j])
				f[i][t[j]]=max(f[i-1][j-1]+t[j]-j+1,f[i][t[j]]);
		}
	}
}

inline void print()
{
	printf("Case #%d: %d\n",cas,f[k][n]);
}

int main()
{
	int t;
	scanf("%d",&t);
	for(cas=1;cas<=t;cas++)
	{
		prework();
		mainwork();
		print();
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/liufengwei1/article/details/83176821
hdu