标签:[[贪心]], [[数学]]
题解:最小代价 01 串转换求和
题意
给定:
- 长度为
N的 01 串S和T。 - 每个位
i有一个代价系数C_i。
操作定义:
每次可以翻转 S 的第 i 位(0→1 或 1→0)。
若此时 S 与 T 有 D 位不同,则本次翻转的代价为 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,T∑f(S,T)(mod109+7).
思路
- 优先修改 C 小的位
代价是D × C_i,显然C_i越小越应该最早修改。
因此将C从小到大排序后,依次考虑每一位的贡献。 - 逐位贡献的拆分
考虑排好序的第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} (jn−i)。
- 对这一位的代价贡献
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=1∑n×2i−1×Ci×j=0∑n−i(jn−i)(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=0∑n−i(jn−i)(j+1)=j=0∑n−i(jn−i)j+j=0∑n−i(jn−i)。
- 利用二项式结论:
∑ ( 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×(k−1r−1)
可得
∑ k ( r k ) = r × 2 r − 1 \sum k\binom{r}{k} = r \times 2^{r-1} ∑k(kr)=r×2r−1。
套入 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=0∑n−i(jn−i)j=(n−i)×2n−i−1。
因此
∑ 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=0∑n−i(jn−i)(j+1)=2n−i+(n−i)×2n−i−1。
答案
将每一位的贡献加总:
∑
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,T∑f(S,T)=2n×i=1∑n×2i−1×Ci×[2n−i+(n−i)×2n−i−1](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)=c1⋅n+c2⋅(n−1)+c3⋅(n−2)+⋯+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)=c2⋅n+c1⋅(n−1)+c3⋅(n−2)+⋯+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),
c1⋅n+c2⋅(n−1)<c2⋅n+c1⋅(n−1),
这等价于
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=1∑mcpi⋅(m−i+1),
其中:
- m m m 表示 S S S 与 T T T 之间 不同位置的数量;
- p i p_i pi 表示排序后第 i i i 个不同的位置。
进一步化简
因为公式中
(
m
−
i
+
1
)
(m - i + 1)
(m−i+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=1∑mcpi⋅i.
这种写法在后续推导中更为便利,也让每个系数
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;
}
585

被折叠的 条评论
为什么被折叠?



