abc题解

E - Change a Little Bit

标签:[[贪心]], [[数学]]

题解:最小代价 01 串转换求和

题意

给定:

  • 长度为 N 的 01 串 ST
  • 每个位 i 有一个代价系数 C_i

操作定义:
每次可以翻转 S 的第 i 位(0→1 或 1→0)。
若此时 STD 位不同,则本次翻转的代价为 D × C_i

定义 f(S,T) 为把 S 变成 T 的最小代价。

∑ S , T f ( S , T ) ( m o d 1 0 9 + 7 ) . \sum_{S,T} f(S,T) \pmod{10^9+7}. S,Tf(S,T)(mod109+7).

思路

  1. 优先修改 C 小的位
    代价是 D × C_i,显然 C_i 越小越应该最早修改。
    因此将 C 从小到大排序后,依次考虑每一位的贡献。
  2. 逐位贡献的拆分
    考虑排好序的第 i 位:
    • S_i = T_i,这一位贡献 0。
    • S_i ≠ T_i,必须修改此位。
      此时之前的不同位已修改完毕,代价仅与后面仍不同的位数有关。
      因此这一位的贡献为
      C i × ( 1 + 后面仍不同的数量 ) 。 C_i \times \bigl(1 + \text{后面仍不同的数量}\bigr)。 Ci×(1+后面仍不同的数量)

公式

i 位之后共有 n - i 位。
设其中 j 位不同,则:

  • 对应方案数 ( n − i j ) \binom{n-i}{j} (jni)
  • 对这一位的代价贡献 C_i × (j + 1)
    i-1 位可以任意选择 S、T,因此贡献中还有 2^n 这一总体倍数。
    于是对第 i 位的总贡献化为:
    2 n × ∑ i = 1 n × 2 i − 1 × C i × ∑ j = 0 n − i ( n − i j ) ( j + 1 ) 2^n \times \sum_{i=1}^{n} \times 2^{i-1}\times C_i \times \sum_{j=0}^{n-i}\binom{n-i}{j}(j+1) 2n×i=1n×2i1×Ci×j=0ni(jni)(j+1)

化简

对核心求和:
∑ j = 0 n − i ( n − i j ) ( j + 1 ) = ∑ j = 0 n − i ( n − i j ) j + ∑ j = 0 n − i ( n − i j ) 。 \sum_{j=0}^{n-i} \binom{n-i}{j}(j+1) = \sum_{j=0}^{n-i}\binom{n-i}{j}j + \sum_{j=0}^{n-i}\binom{n-i}{j}。 j=0ni(jni)(j+1)=j=0ni(jni)j+j=0ni(jni)

  • 利用二项式结论:
    ∑ ( r k ) = 2 r \sum \binom{r}{k} = 2^r (kr)=2r
  • 利用吸收恒等式:
    ( r k ) × k = r × ( r − 1 k − 1 ) \binom{r}{k}\times k = r \times \binom{r-1}{k-1} (kr)×k=r×(k1r1)
    可得
    ∑ k ( r k ) = r × 2 r − 1 \sum k\binom{r}{k} = r \times 2^{r-1} k(kr)=r×2r1
    套入 r = n-i:
    ∑ j = 0 n − i ( n − i j ) j = ( n − i ) × 2 n − i − 1 。 \sum_{j=0}^{n-i} \binom{n-i}{j} j = (n - i) \times 2^{n-i-1}。 j=0ni(jni)j=(ni)×2ni1
    因此
    ∑ j = 0 n − i ( n − i j ) ( j + 1 ) = 2 n − i + ( n − i ) × 2 n − i − 1 。 \sum_{j=0}^{n-i}\binom{n-i}{j}(j+1) = 2^{n-i} + (n-i)\times 2^{n-i-1}。 j=0ni(jni)(j+1)=2ni+(ni)×2ni1

答案

将每一位的贡献加总:
∑ S , T f ( S , T ) = 2 n × ∑ i = 1 n × 2 i − 1 × C i × [ 2 n − i + ( n − i ) × 2 n − i − 1 ] ( m o d 1 0 9 + 7 ) . \sum_{S,T} f(S,T) = 2^n \times \sum_{i=1}^{n} \times 2^{i-1}\times C_i \times \bigl[ 2^{n-i} + (n-i)\times 2^{n-i-1}\bigr] \pmod{10^9+7} . S,Tf(S,T)=2n×i=1n×2i1×Ci×[2ni+(ni)×2ni1](mod109+7).

贪心正确性证明

排序不等式的直观证明

显而易见,若把 c i c_i ci 较小的数放在前面,不会使总代价更大。
我们可以用 排序不等式 来严格证明这一点。

证明过程

假设 S S S T T T 没有任何一位相等,此时
f ( S , T ) = c 1 ⋅ n + c 2 ⋅ ( n − 1 ) + c 3 ⋅ ( n − 2 ) + ⋯ + c n . f(S,T)=c_1\cdot n + c_2\cdot (n-1) + c_3\cdot (n-2) + \dots + c_n. f(S,T)=c1n+c2(n1)+c3(n2)++cn.
如果我们交换 c 1 c_1 c1 c 2 c_2 c2 的顺序,则
f ′ ( S , T ) = c 2 ⋅ n + c 1 ⋅ ( n − 1 ) + c 3 ⋅ ( n − 2 ) + ⋯ + c n . f'(S,T) = c_2 \cdot n + c_1 \cdot (n-1) + c_3 \cdot (n-2) + \dots + c_n. f(S,T)=c2n+c1(n1)+c3(n2)++cn.
若要满足 f ( S , T ) < f ′ ( S , T ) f(S,T) < f'(S,T) f(S,T)<f(S,T),则需要
c 1 ⋅ n + c 2 ⋅ ( n − 1 ) < c 2 ⋅ n + c 1 ⋅ ( n − 1 ) , c_1 \cdot n + c_2 \cdot (n-1) < c_2 \cdot n + c_1 \cdot (n-1), c1n+c2(n1)<c2n+c1(n1),
这等价于
c 1 < c 2 . c_1 < c_2. c1<c2.
因此,把较小的 c i c_i ci 排在前面 最优

公式化结果

所以按照 c i c_i ci 从小到大排序后,有
f ( S , T ) = ∑ i = 1 m c p i ⋅ ( m − i + 1 ) , f(S,T) = \sum_{i=1}^{m} c_{p_i} \cdot (m - i + 1), f(S,T)=i=1mcpi(mi+1),
其中:

  • m m m 表示 S S S T T T 之间 不同位置的数量
  • p i p_i pi 表示排序后第 i i i 个不同的位置。

进一步化简

因为公式中 ( m − i + 1 ) (m - i + 1) (mi+1) 的括号看着比较别扭,可以反向思考:
若我们改为把 c i c_i ci 从大到小排序,则有
f ( S , T ) = ∑ i = 1 m c p i ⋅ i . f(S,T) = \sum_{i=1}^{m} c_{p_i} \cdot i. f(S,T)=i=1mcpii.
这种写法在后续推导中更为便利,也让每个系数 i i i 的增长顺序更直观。


时空复杂度:O(n log n) O(n)

核心代码

int n,ans;
int c[N];
  
void solve()
{
    cin >> n;
    for(int i=1;i<=n;i++)
        cin >> c[i];
    sort(c+1,c+n+1);
    for(int i=1;i<=n;i++)
    {
        int p1=quickPow(2,i-1,MOD);
        int p2=quickPow(2,n-i,MOD);
        int add=0;
        if (n-i>=1)
            add=(((n-i)%MOD)*quickPow(2,n-i-1,MOD))% MOD;
        int sum1=(p2+add)%MOD;
        int tmp=p1;
        tmp=((tmp*(c[i]%MOD))%MOD);
        tmp=(tmp*sum1)%MOD;
        ans=(ans+tmp)%MOD;
    }
    cout << (ans*quickPow(2,n,MOD))%MOD << endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值