将每个球按输入顺序编号,建立 它第几个被扔掉->编号 的映射关系。
记录当前在手里的球的编号,按扔掉的顺序查找这个球的编号,看看这个球是逆时针转到手里更近还是顺时针转到手里更近,即当前扔掉球的编号与当前手里球的编号之间有几个球。
树状数组C[i]记录编号i的球是否还在。
球是环形排列的,特殊处理一下。
对于扔掉一个球之后下一个落在手里的球的编号,二分判定,找顺时针方向第一个有球的位置
#include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #define LL long long int using namespace std; const int MAXN = 100100; int C[MAXN]; int N; int PosToID[MAXN]; int IDToPos[MAXN]; int lowbit( int x ) { return x & ( -x ); } int query( int x ) { if ( !x ) return 0; int res = 0; while ( x > 0 ) { res += C[x]; x -= lowbit(x); } return res; } void update( int x, int val ) { while ( x <= N ) { C[x] += val; x += lowbit(x); } return; } int BiSearch( int l, int r ) { int pre = l; if ( query(r) - query(l) == 0 ) { r = l; l = 1; pre = 0; } int ans = 0; while ( l <= r ) { int mid = ( l + r ) >> 1; if ( query(mid) - query(pre) > 0 ) { ans = mid; r = mid - 1; } else l = mid + 1; } return ans; } int main() { while ( scanf( "%d", &N ), N ) { memset( C, 0, sizeof(C) ); for ( int i = 1; i <= N; ++i ) { scanf("%d", &IDToPos[i] ); PosToID[ IDToPos[i] ] = i; update( i, 1 ); } int cur = 1; //当前手里的 LL ans = 0; for ( int i = 1; i <= N; ++i ) { int id = PosToID[i]; if ( id < cur ) { int tmp = query(cur) - query(id); ans += min( tmp, query(N) - query(cur) + query(id) ); } else if ( id > cur ) { int tmp = query(id) - query(cur); ans += min( tmp, query(N) - query(id) + query(cur) ); } update( id, -1 ); ++ans; cur = BiSearch( id, N ); } printf( "%I64d\n", ans ); } return 0; }