【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;
}

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