【Atcoder】AGC023 C-F简要题解

版权声明:欢迎转载(请附带原链接)ヾ(๑╹◡╹)ノ https://blog.csdn.net/corsica6/article/details/88827868

*C.Painting Machines

不好求得分为恰好为 i i 的排列个数,则考虑转化为求解得分 i \geq i 的排列个数 g [ i ] g[i] a n s = i = 1 n g [ i ] ans=\sum \limits_{i=1}^ng[i]

很容易得到得分 i \leq i 的有序排列个数 w [ i ] w[i]
1 , n 1 P 1,n-1\in P ,而其它数差分后的值 { 1 , 2 } \in \{1,2\} 。因为操作次数是固定的,且 1 + 2 = n 2 \sum 1+\sum 2=n-2 ,所以 1 , 2 1,2 的个数也是固定的,设分别为 c n t 0 , c n t 1 cnt_0,cnt_1 ,则 w [ i ] = ( i 1 ) ! c n t 0 ! c n t 1 ! w[i]=\dfrac{(i-1)!}{cnt_0!cnt_1!}

容斥求出所有得分 > i >i ( i + 1 \geq i+1 )的排列个数 ( ( n 1 i 1 ) w [ i ] ) i ! ( n i ) ! ({n-1\choose i-1}-w[i])i!(n-i)!


*D.Go Home

每次贪心选期望最大显然倒序做,DP的复杂度做不了,观察出以下性质:

考虑只剩下两个最远处的位置 l , r l,r 没到的状态:

  • 如果它们在车的同侧,直接把车开过去即可。

  • 否则假设 P a > P b P_a>P_b ,必然存在 T b = T a + d i s ( X a , X b ) T_b=T_a+dis(X_a,X_b) ,所以在 a a 到达前, b b 一定会一直帮着 a a ,使得 T a T_a 尽量小,从而 T b T_b 尽量小。

可以倒序构造,维护 L , R L,R ,初始化 L = 1 , R = n L=1,R=n ,当 L , R L,R 在车的一侧时终止,否则若 P L P R P_L\geq P_R ,在到达 L L 前, L L 的意志完全代表 R R 的意志,于是 P L + = P R P_L+=P_R ,然后 R R-- P L < P R P_L<P_R 的情况同理可得。

具体可以看一下代码
code from sigongzi

#include <iostream>
#include <cstdio>
#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;
}


*E.Inversions

统计合法全排列个数的方法:

c n t i cnt_i 表示 A i A\geq i 的位置个数,考虑从大到小选数,方案数即 i = 1 n ( c n t i ( n i ) ) \prod\limits_{i=1}^n (cnt_i-(n-i))

枚举逆序对,强制 i &lt; j , P i &gt; P j i&lt;j,P_i&gt;P_j ,分类讨论:

  • A i &lt; A j A_i&lt;A_j ,强制 A j : = A i A_j:=A_i ,贡献为合法排列数 / 2 /2
  • A i A j A_i\geq A_j ,贡献为总排列数-(强制 A i : = A j A_i:=A_j 后的合法排列数/2)

考虑按权值从大往小做,维护以位置为下标的BIT
c n t = 0 cnt=0 的地方切开分成若干段,每段中强制 A i : = A j A_i:=A_j 时, c n t A j + 1... A i cnt_{A_j+1...A_i} 一段相当于乘上了 c n t 1 c n t \dfrac{cnt-1}{cnt} ,注意判断区间存在 c n t = 1 cnt=1 的情况,


*F.01 on Tree

一种比较经典的贪心方式

设点 x x 子树内 0 0 的个数为 f ( x ) f(x) 1 1 的个数为 g ( x ) g(x) ,显然先走 f ( x ) g ( x ) \dfrac{f(x)}{g(x)} 最大的点

单点的情况是固定的,可以用大根堆存储,每次弹出堆顶点 i i

  • f a i = 0 fa_i=0 ( i i 为根),则删去 i i 后继续弹堆
  • 否则 f a i fa_i 还没有走过,根据贪心走到 f a i fa_i 后一定会立刻进入 i i ,贡献为 g ( f a i ) f ( i ) g(fa_i)f(i) ,那么 i , f a i i,fa_i 就是一体的了,并查集缩成一个点后重新压入堆

猜你喜欢

转载自blog.csdn.net/corsica6/article/details/88827868