不好求得分为恰好为 i i i的排列个数,则考虑转化为求解得分 ≥ i \geq i ≥i的排列个数 g [ i ] g[i] g[i], a n s = ∑ i = 1 n g [ i ] ans=\sum \limits_{i=1}^ng[i] ans=i=1∑ng[i]。
很容易得到得分 ≤ i \leq i ≤i的有序排列个数 w [ i ] w[i] w[i]:
1 , n − 1 ∈ P 1,n-1\in P 1,n−1∈P,而其它数差分后的值 ∈ { 1 , 2 } \in \{1,2\} ∈{1,2}。因为操作次数是固定的,且 ∑ 1 + ∑ 2 = n − 2 \sum 1+\sum 2=n-2 ∑1+∑2=n−2,所以 1 , 2 1,2 1,2的个数也是固定的,设分别为 c n t 0 , c n t 1 cnt_0,cnt_1 cnt0,cnt1,则 w [ i ] = ( i − 1 ) ! c n t 0 ! c n t 1 ! w[i]=\dfrac{(i-1)!}{cnt_0!cnt_1!} w[i]=cnt0!cnt1!(i−1)!
容斥求出所有得分 > i >i >i( ≥ i + 1 \geq i+1 ≥i+1)的排列个数 ( ( n − 1 i − 1 ) − w [ i ] ) i ! ( n − i ) ! ({n-1\choose i-1}-w[i])i!(n-i)! ((i−1n−1)−w[i])i!(n−i)!。
每次贪心选期望最大显然倒序做,DP的复杂度做不了,观察出以下性质:
考虑只剩下两个最远处的位置 l , r l,r l,r没到的状态:
如果它们在车的同侧,直接把车开过去即可。
否则假设 P a > P b P_a>P_b Pa>Pb,必然存在 T b = T a + d i s ( X a , X b ) T_b=T_a+dis(X_a,X_b) Tb=Ta+dis(Xa,Xb),所以在 a a a到达前, b b b一定会一直帮着 a a a,使得 T a T_a Ta尽量小,从而 T b T_b Tb尽量小。
可以倒序构造,维护 L , R L,R L,R,初始化 L = 1 , R = n L=1,R=n L=1,R=n,当 L , R L,R L,R在车的一侧时终止,否则若 P L ≥ P R P_L\geq P_R PL≥PR,在到达 L L L前, L L L的意志完全代表 R R R的意志,于是 P L + = P R P_L+=P_R PL+=PR,然后 R − − R-- R−−, P L < P R P_L<P_R PL<PR的情况同理可得。
具体可以看一下代码
code from sigongzi
#include
#include
#define MAXN 100005
//#define ivorysi
using namespace std;
typedef long long int64;
typedef double db;
int N;
int64 S,X[MAXN],P[MAXN],ans;
void Solve() {
scanf("%d%lld",&N,&S);
for(int i = 1 ; i <= N ; ++i) {
scanf("%lld%lld",&X[i],&P[i]);
}
int L = 1,R = N;
int dir = 0;
while(1) {
if(X[L] >= S) {ans += X[R] - S;break;}
if(X[R] <= S) {ans += S - X[L];break;}
if(P[L] >= P[R]) {
if(dir != 1) {dir = 1;ans += X[R] - X[L];}
P[L] += P[R];R--;
}
else {
if(dir != 2) {dir = 2;ans += X[R] - X[L];}
P[R] += P[L];L++;
}
}
printf("%lld\n",ans);
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Solve();
return 0;
}
统计合法全排列个数的方法:
设 c n t i cnt_i cnti表示 A ≥ i A\geq i A≥i的位置个数,考虑从大到小选数,方案数即 ∏ i = 1 n ( c n t i − ( n − i ) ) \prod\limits_{i=1}^n (cnt_i-(n-i)) i=1∏n(cnti−(n−i))
枚举逆序对,强制 i < j , P i > P j i<j,P_i>P_j i<j,Pi>Pj,分类讨论:
考虑按权值从大往小做,维护以位置为下标的BIT
从 c n t = 0 cnt=0 cnt=0的地方切开分成若干段,每段中强制 A i : = A j A_i:=A_j Ai:=Aj时, c n t A j + 1... A i cnt_{A_j+1...A_i} cntAj+1...Ai一段相当于乘上了 c n t − 1 c n t \dfrac{cnt-1}{cnt} cntcnt−1,注意判断区间存在 c n t = 1 cnt=1 cnt=1的情况,
一种比较经典的贪心方式
设点 x x x子树内 0 0 0的个数为 f ( x ) f(x) f(x), 1 1 1的个数为 g ( x ) g(x) g(x),显然先走 f ( x ) g ( x ) \dfrac{f(x)}{g(x)} g(x)f(x)最大的点
单点的情况是固定的,可以用大根堆存储,每次弹出堆顶点 i i i: