【noi.ac #1999】摔跤

题目

Description
NN个精灵和NN个矮人正在举行摔跤大赛。NN个矮人顺时针依次站在一个圆周上。

第ii个精灵将要和第AiAi个矮人摔跤。然而,由于主办方的失误,AA中可能有相同的元素。精灵将按照一定的顺序入场。入场的xx号精灵将优先和AxAx号矮人摔跤,但如果当前矮人已经和其他精灵摔过跤了,xx号精灵将尝试和顺时针方向的下一个矮人摔跤,以此类推,直到找到一个还没有摔过跤的矮人。

ii号矮人的力量值为PiPi,ii号精灵的力量值为ViVi。所有的力量值两两不同。在摔跤时,力量值高的一方一定会获胜。精灵们想知道,如果妥善安排入场顺序,最多有多少精灵获胜?

Input format
第一行一个整数NN(1≤N≤5×105)1≤N≤5×105)。 第二行NN个整数,第ii个表示AiAi(1≤Ai≤N1≤Ai≤N)。 第三行NN个整数,第ii个表示PiPi(1≤Pi≤1091≤Pi≤109)。 第四行NN个整数,第ii个表示ViVi(1≤Ai≤1091≤Ai≤109)。

Output format
一行一个整数,表示精灵最多胜利的次数。

Sample input 1
3
2 3 3
4 1 10
2 7 3
Sample output 1
2
Sample input 2
4
3 1 3 3
5 8 7 10
4 1 2 6
Sample output 2
1
Sample input 3
3
1 2 3
8 4 3
9 2 6
Sample output 3
2
Constrains
本题采用子任务的方式评测。

子任务一(20pts20pts):保证Ai=1Ai=1。

子任务二(30pts30pts):保证N≤1000N≤1000。

子任务三(50pts50pts):没有额外限制。

思路

若有kkAi=xA_i=x,记Sx=k1S_x=k-1。可以发现,i=1nSi=0\sum\limits_{i=1}^{n}S_i=0。考虑SS的前缀和最小的位置,可以发现,不管顺序如何,一定没有精灵顺时针越过这个位置。于是环的问题就变成了序列的问题。我们可以对序列进行贪心:从后往前,对于每个精灵,如果它能赢以后的某个矮人,就让它对抗它能赢的最强的矮人,否则让它对抗最强的矮人。用set维护能力值,复杂度为O(nlogn)O(n \log n)

代码

#include <set>
#include <cstdio>
#include <vector>

inline int rint () {
	int x = 0, f = 1; char s = getchar ();
	for ( ; s < '0' || '9' < s; s = getchar () ) f = s == '-' ? -f : f;
	for ( ; '0' <= s && s <= '9'; s = getchar () ) x = x * 10 + ( s ^ '0' );
	return x * f;
}

template<typename Tp>
inline void wint ( Tp x ) {
	if ( x < 0 ) putchar ( '-' ), x = ~ x + 1;
	if ( 9 < x ) wint ( x / 10 );
	putchar ( x % 10 ^ '0' );
}

const int MAXN = 5e5;
int N, A[MAXN + 5], P[MAXN + 5], V[MAXN + 5];
std :: vector<int> val[MAXN + 5];
std :: set<int> st;

inline int nxt ( const int i ) { return i % N + 1; }

int main () {
	N = rint ();
	for ( int i = 1; i <= N; ++ i ) A[i] = rint ();
	for ( int i = 1; i <= N; ++ i ) P[i] = rint ();
	for ( int i = 1; i <= N; ++ i ) val[A[i]].push_back ( V[i] = rint () );
	int p = -1, mns = N;
	for ( int i = 1, s = 0; i <= N; ++ i ) {
		s += int ( val[i].size () ) - 1;
		if ( mns > s ) p = nxt ( i ), mns = s;
	}
	int ans = 0;
	for ( int i = p, stp = N; stp --; i = nxt ( i ) ) {
		for ( int ele: val[i] ) st.insert ( ele );
		std :: set<int> :: iterator it ( st.lower_bound ( P[i] ) );
		if ( it != st.end () ) ++ ans, st.erase ( it );
		else st.erase ( st.begin () );
	}
	printf ( "%d\n", ans );
	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章