CF39C Moon Craters

一、题目

点此看题

二、解法

把每个圆表示成线段覆盖,判断相不相交只需要比较大小,所以我们可以先离散化。

考虑使用区间 d p dp dp,但一定要想清楚区间指的是什么,一开始我把区间理解成连续的若干个圆,发现根本做不动。而本题显然把区间理解成数轴上的区间更好做,定义 d p [ i ] [ j ] dp[i][j] dp[i][j]为区间 [ i , j ] [i,j] [i,j]最多的圆数量,转移:
d p [ i ] [ j ] = d p [ i ] [ x ] + d p [ x ] [ j ] + g [ i ] [ j ] dp[i][j]=dp[i][x]+dp[x][j]+g[i][j] dp[i][j]=dp[i][x]+dp[x][j]+g[i][j] g [ i ] [ j ] g[i][j] g[i][j]表示是否存在一个左边界为 i i i,右边界为 j j j的圆, x x x需要枚举,咋一看这个复杂度是 O ( n 3 ) O(n^3) O(n3)的,但是 x x x只可能取到圆的边界。我们不妨从圆的角度分析复杂度,有 n n n个圆,每个圆扩展 n n n次(必须要圆的左边界和 i i i一样才拓展),所以复杂度是 O ( n 2 ) O(n^2) O(n2)的。

输出具体方案记录下划分点就行了。

#include 
#include 
#include 
using namespace std;
const int M = 4005;
int read()
{
    int x=0,flag=1;char c;
    while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
    while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*flag;
}
int n,m,x[M],y[M],d[M],dp[M][M],g[M][M],f[M][M];
vector<int> b[M];
void print(int l,int r)
{
	if(!dp[l][r] || l>r) return ;
	if(f[l][r]) print(l,f[l][r]),print(f[l][r],r);
	else print(l+1,r);
	if(g[l][r]) printf("%d ",g[l][r]);
}
int main()
{
	n=read();
	for(int i=1;i<=n;i++)
	{
		int c=read(),r=read();
		x[i]=d[++m]=c-r;
		y[i]=d[++m]=c+r;
	}
	sort(d+1,d+1+m);
	m=unique(d+1,d+1+m)-d-1;
	for(int i=1;i<=n;i++)
	{
		x[i]=lower_bound(d+1,d+1+m,x[i])-d;
		y[i]=lower_bound(d+1,d+1+m,y[i])-d;
		b[x[i]].push_back(y[i]);
		g[x[i]][y[i]]=i;
	}
	for(int i=m;i>=1;i--)
		for(int j=i;j<=m;j++)
		{
			dp[i][j]=dp[i+1][j];
			for(int k=0;k<b[i].size();k++)
			{
				int x=b[i][k];
				if(x<j && dp[i][x]+dp[x][j]>dp[i][j])
				{
					dp[i][j]=dp[i][x]+dp[x][j];
					f[i][j]=x;
				}
			}
			dp[i][j]+=(g[i][j]>0?1:0);
		}
	printf("%d\n",dp[1][m]);
	print(1,m);
}

你可能感兴趣的:(区间dp)