1. 程式人生 > 其它 >noip模擬31 Game Time Cover

noip模擬31 Game Time Cover

noip模擬31 Game Time Cover

考場上順序開題。

\(\mathrm{A.}\mathbb{Game}\):資料結構

\(\mathrm{B.}\mathbb{Time}\):資料結構

\(\mathrm{C.}\mathbb{Cover}\):樹形 \(\mathrm{dp}\)

首看 \(\mathrm{A}\),發現很容易求出其中一種情況,於是又繞進去了,不過在大約一個小時的時候發現了億些問題,於是便轉 \(\mathrm{B}\) 了。(事實上按照這個思路是能打一部分分的,但是最後也沒調出來)

\(\mathrm{B}\) 時,也有一定的思路,由於以前做過一道類似的題,便考慮最大值,期間也考慮過最小值,但當時並不知道如何貪心,於是便叉掉了。

\(\mathrm{C}\) 沒看幾眼,只看出來可以建成樹的形式,沒有細想。

最後的一個小時主要還是卡在 \(\mathrm{A}\) 上了,資料結構還是應用的不夠熟練,應該多做些題,大膽嘗試使用資料結構(

估分:\([0,100]+0+0=[0,100]\)

實際:\(10+0+0=10\)

還是說正解吧(

\(\mathrm{A.}\mathbb{Game}\)

正解

\(\mathrm{B.}\mathbb{Time}\)

考場上考慮答案為最大值移動後所分成的兩個區間以及最大值移動的運算元之和,以為最大值移動的次數越少越好,很明顯是假的(

正解

考慮最小值,只能在序列的最左邊或是最右邊,每次貪心的選擇更優(運算元更少)的那一邊,將運算元累計到答案裡,再去掉這個點,解決子問題。

\(\mathrm{deque}\) 以值為下標,把位置存進去,按照值域從小到大掃一遍。

需要單獨考慮有值相同的情況,每次取出隊首與隊尾,比較它們誰更優,然後再將其彈出。

由於需要查詢刪去數之後的排名,因此用一個線段樹(或樹狀陣列),來支援單點修改和區間查詢的操作。

code
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n;
int l,r,mx;
deque<int> q[N];
long long ans;
struct Tree
{
	int l,r;
	int sum;
}tree[N*4];
void pushup(int p)
{
	tree[p].sum=tree[p*2].sum+tree[p*2+1].sum;
	return;
}
void build(int p,int l,int r)
{
	tree[p].l=l;
	tree[p].r=r;
	if(l==r)
	{
		tree[p].sum=1;
		return;
	}
	int mid=(l+r)/2;
	build(p*2,l,mid);
	build(p*2+1,mid+1,r);
	pushup(p);
	return;
}
int ask(int p,int l,int r)
{
	if(tree[p].l>=l&&tree[p].r<=r) return tree[p].sum;
	int mid=(tree[p].l+tree[p].r)/2;
	int sum=0;
	if(l<=mid) sum+=ask(p*2,l,r);
	if(r>=mid+1) sum+=ask(p*2+1,l,r);
	return sum;
}
void change(int p,int l,int r,int d)
{
	if(tree[p].l>=l&&tree[p].r<=r)
	{
		tree[p].sum+=d;
		return;
	}
	int mid=(tree[p].l+tree[p].r)/2;
	if(l<=mid) change(p*2,l,r,d);
	if(r>=mid+1) change(p*2+1,l,r,d);
	pushup(p);
	return;
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		int x;
		scanf("%d",&x);
		q[x].push_back(i);
		mx=max(mx,x);
	}
	build(1,1,n);
	for(int i=1;i<=mx;i++)
	{
		while(q[i].size())
		{
			int l=q[i].front(),r=q[i].back();
			int a=ask(1,1,l-1),b=ask(1,r+1,n);
			if(a<b)
			{
				ans+=a;
				change(1,l,l,-1);
				q[i].pop_front();
			}
			else
			{
				ans+=b;
				change(1,r,r,-1);
				q[i].pop_back();
			}
		}
	}
	printf("%d\n",ans);
	return 0;
}

\(\mathrm{C.}\mathbb{Cover}\)

正解