Codeforces Round #245 (Div. 1)——Tricky Function

题目链接

  • 题意:
    n个数a[i],f(i, j) = (i - j) ^ 2 + sigma(a[k]) ^ 2, i < k <= j,求最小的f值
    n (2 ≤ n ≤ 100000).( - 104 ≤ a[i] ≤ 104)
  • 分析:
    关键在于题意的转换。简单的考虑,需要知道每个区间的信息,复杂度难以降下来,应该将题目的f函数进行化简。既然考虑区间是不可行的,那么就尝试是否能将区间分成两个短点的计算。这里用到了一个常用的转换:区间和转化为前缀和的差。转换后就得到f(i, j) = (i - j) ^ 2 + (presum[j] - presum[i]) ^ 2,做过几何的都能看出来,就是平面最近点对
  • 总结:
    如果以区间为问题的单位,那么复杂度难以下降,所以问题的考虑单位往往是点,如果能转化为点,复杂度将可以下降
    区间和往往需要转化为前缀和:这样的话,对于区间的两个点,需要求得值就只和当前点有关,也就是完成了上一个(区间转化为点)的任务

const double EPS = 1e-10;
const int MAXN = 100100;

inline int dcmp(double x)
{
	if(fabs(x) < EPS) return 0;
	else return x < 0 ? -1 : 1;
}
struct Point
{
	LL x, y;
};

//最近点对
Point point[MAXN];
LL tmpt[MAXN], Y[MAXN];

inline bool cmpxy(Point a, Point b)
{
	if(a.x != b.x)
		return a.x < b.x;
	return a.y < b.y;
}

inline bool cmpy(int a, int b)
{
	return point[a].y < point[b].y;
}

inline LL dist(int x, int y)
{
	Point& a = point[x], &b = point[y];
	return sqr(a.x - b.x) + sqr(a.y - b.y);
}

LL Closest_Pair(int left, int right)
{
	LL d = 1e18;
	if(left == right)
		return d;
	if(left + 1 == right)
		return dist(left, right);
	int mid = (left + right) >> 1;
	double d1 = Closest_Pair(left, mid);
	double d2 = Closest_Pair(mid + 1, right);
	d = min(d1, d2);
	int k = 0;
	//分离出宽度为d的区间
	FE(i, left, right)
	{
		if(sqr(point[mid].x - point[i].x) <= d)
			tmpt[k++] = i;
	}
	sort(tmpt, tmpt + k, cmpy);
	//线性扫描
	REP(i, k)
		for(int j = i + 1; j < k && sqr(point[tmpt[j]].y-point[tmpt[i]].y) < d; j++)
		{
			LL d3 = dist(tmpt[i],tmpt[j]);
			if(d > d3)
				d = d3;
		}
	return d;
}

LL ipt[MAXN];
int main()
{
	//freopen("input.txt", "r", stdin);
	int n;
	while (~RI(n) && n)
	{
		FE(i, 1, n)
		{
			cin >> ipt[i];
			ipt[i] = ipt[i - 1] + ipt[i];
		}
		FE(i, 1, n)
		{
			point[i - 1].x = i;
			point[i - 1].y = ipt[i];
		}
		sort(point, point + n, cmpxy);
		LL ans = Closest_Pair(0, n - 1);
		cout << ans << endl;
	}
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值