UCF Local Programming Contest 2017 I. Rotating Cards

在这里插入图片描述
在这里插入图片描述

题意:

有一堆数字 1   n 1~n 的卡片,你需要按照数字 1   n 1~n 的顺序将他们删去。你只能删去最上面的那张卡片,但你可以将最上面的卡片移动到最底部,也可以将最底部的卡片移动到最上面,问移动次数最少是多少。
很显然,想删去一张卡片,要么把它上面的所有卡片移动到底部,要么从底部将它拿上来。如果将这堆卡片的最上面和底部看作是首尾相连的,那么不管怎么移动,所有卡片的相对位置都是不变的。
用线段树或树状数组,区间查询,单点修改。对于删去第 k k 张卡片,这个时候是第k-1张卡片在顶部。区间查询两张卡片之间剩余的卡片数量,就是将第 k k 张卡片从上或从下(取决于这两张卡片一开始的相对位置)移动到顶部的移动次数 a n k a a,n-k-a 就是另一种移动方式的代价,取较小的那个。然后单点修改删去这张牌。

AC代码:

const int N = 1e5 + 10;
struct node
{
	ll a;
	int pos;
} s[N];
ll tr[N];
int n;

void add(int x, ll c)
{
	int i;
	for (i = x; i <= n; i += lowbit(i))
	{
		tr[i] += c;
	}
}

ll sum(int x)
{
	int i;
	ll res = 0;
	for (i = x; i; i -= lowbit(i))
	{
		res += tr[i];
	}
	return res;
}
bool cmp(node a, node b)
{
	return a.a < b.a;
}
int main()
{
	int t;
	sd(t);
	while (t--)
	{
		sd(n);
		rep(i, 1, n)
		{
			sld(s[i].a);
			s[i].pos = i;
			add(i, s[i].a);
		}
		ll ans = 0;
		sort(s + 1, s + 1 + n, cmp);
		int pos = s[1].pos;
		ans += min(sum(s[1].pos - 1), sum(n) - sum(s[1].pos - 1));
		add(s[1].pos, -s[1].a);
		rep(i, 2, n)
		{
			int tmp = s[i].pos;
			ll up;
			ll down;
			if (tmp < pos)
			{
				up = sum(tmp - 1) + sum(n) - sum(pos - 1);
				down = sum(pos) - sum(tmp - 1);
			}
			else
			{
				up = sum(tmp - 1) - sum(pos);
				down = sum(n) - sum(tmp - 1) + sum(pos);
			}
			ans += min(up, down);
			add(tmp, -s[i].a);
			pos = tmp;
		}
		pld(ans);
	}
	return 0;
}
发布了786 篇原创文章 · 获赞 460 · 访问量 24万+

猜你喜欢

转载自blog.csdn.net/qq_43627087/article/details/105349913