[AGC023D] Go Home
题目
点这里看题目。
分析
一眼望过去似乎就是每个人往自己的家的方向投?
幸好出题人够良心,光是样例 1 就帮你把这个错误的想法叉掉了
每个人往自己家投,前提条件是自己的票可以让自己尽早回家。
比如,\(n\) 楼居民如果盲目向右跟风,那么很有可能投着投着,还没回到家,就因为投右的人都走得差不多了,结果反被拉着向左走,回家的时间反而变晚了。
又考虑到最后到家的人要么是第 1 幢楼的人,要么是第 \(n\) 幢楼的人。如果有 \(p_1\ge p_n\),那么在某次投票中,\(n\) 楼居民一定会被迫跟着 1 楼居民走;而显然 1 楼居民不到家,他们就到不了家,因此他们一定会全力支持 1 楼居民提早回家。考虑到 \(n\) 楼居民的策略现在一定和 1 楼居民的策略基本一致,我们可以看作是将 \(n\) 楼居民搬迁到了 1 楼,最后再搬回 \(n\) 楼。
相似的,当 \(p_1< p_n\) 的时候,一定是 1 楼居民全力支持 \(n\) 楼居民,而 \(n\) 楼居民可能最后可以夺取掌控权,暂时还无法论断。
那么,进行“搬迁”操作后我们得到了相似的子问题,可以递归解决,时间为 \(O(n)\)。
得出结论,人多才是硬道理
小结:
- 分析多个对象的问题,可以抓住关键的几个对象来分析他们的策略;
- 相似问题、递归思想;
- 其中“将 \(n\) 楼居民搬迁到 1 楼”,这个想法很有趣;
代码
#include <set>
#include <cstdio>
using namespace std;
#define rep( i, a, b ) for( int i = (a) ; i <= (b) ; i ++ )
#define per( i, a, b ) for( int i = (a) ; i >= (b) ; i -- )
typedef long long LL;
const int MAXN = 1e5 + 5;
template<typename _T>
void read( _T &x )
{
x = 0; char s = getchar(); int f = 1;
while( s < '0' || '9' < s ) { f = 1; if( s == '-' ) f = -1; s = getchar(); }
while( '0' <= s && s <= '9' ) { x = ( x << 3 ) + ( x << 1 ) + ( s - '0' ), s = getchar(); }
x *= f;
}
template<typename _T>
void write( _T x )
{
if( x < 0 ) putchar( '-' ), x = -x;
if( 9 < x ) write( x / 10 );
putchar( x % 10 + '0' );
}
template<typename _T>
_T ABS( const _T a )
{
return a < 0 ? -a : a;
}
LL X[MAXN], P[MAXN];
int N, S; LL ans = 0;
int Solve( const int l, const int r )
{
if( S <= X[l] ) return ans += X[r] - S, X[r];
if( S >= X[r] ) return ans += S - X[l], X[l];
if( P[l] >= P[r] )
{
P[l] += P[r];
int t = Solve( l, r - 1 );
ans += X[r] - t;
return X[r];
}
else
{
P[r] += P[l];
int t = Solve( l + 1, r );
ans += t - X[l];
return X[l];
}
}
int main()
{
read( N ), read( S );
rep( i, 1, N )
read( X[i] ), read( P[i] );
Solve( 1, N );
write( ans ), putchar( '\n' );
return 0;
}