欢迎光临
我们一直在努力

The 2025 ICPC Asia East Continent Online Contest (II) D题(数学)

题目链接:奥术巨兽 – 题目 – QOJ.ac

题目大意:给定一个数组,可以选择该数组的任意非空子序列,当该子序列出售一个元素时,其他元素可以加上失去元素的值,一个子序列的价值定义为:如果以最优的顺序售出该子序列中的其他巨兽,最后剩下的一只巨兽所能达到的最大攻击力。计算该序列所有非空子序列的价值之和。请将结果模 998244353 后输出。

题目思路:

对于子序列只有2个元素时:

例1:子序列 [1, 2]

  • 取最大 2 → [1+2] = [3]

  • 价值 = 3 = 1 + 2

例2:子序列 [1, 3]

  • 取最大 3 → [1+3] = [4]

  • 价值 = 4 = 1 + 3

例3:子序列 [2, 3]

  • 取最大 3 → [2+3] = [5]

  • 价值 = 5 = 2 + 3

结论1:对于长度为 2 的子序列 [a, b](a ≤ b),价值 = a + b

对于子序列元素大于2个时:

例4:子序列 [1, 2, 3]

  • 取最大 3 → [1+3, 2+3] = [4, 5]

  • 取最大 5 → [4+5] = [9]

  • 价值 = 9 = 1 + 2 + 2×3

例5:子序列 [1, 4, 6]

  • 取最大 6 → [1+6, 4+6] = [7, 10]

  • 取最大 10 → [7+10] = [17]

  • 价值 = 17 = 1 + 4 + 2×6

例6:子序列 [1, 2, 3, 4]

  • 取最大 4 → [1+4, 2+4, 3+4] = [5, 6, 7]

  • 取最大 7 → [5+7, 6+7] = [12, 13]

  • 取最大 13 → [12+13] = [25]

  • 价值 = 25 = 1 + 2 + 2×3 + 4×4

一般规律

对于升序排列的子序列 [a₁, a₂, a₃, …, aₖ](a₁ ≤ a₂ ≤ … ≤ aₖ),其价值为:

价值 = a₁ + a₂ + 2×a₃ + 4×a₄ + 8×a₅ + … + 2^(k-2)×aₖ

虽然现在有计算每个子序列价值的公式了,但是枚举每个子序列显然是会超时的,那么我们可以使用贡献法:

对数组排序后,考虑位置 i 的元素 A[i],它前面有 i 个比它小的元素,后面有 N-1-i 个比它大的元素。

        对于包含 A[i] 的子序列:

  • 从前面 i 个元素中选 t 个(0 ≤ t ≤ i)

  • 从后面 N-1-i 个元素中任选(每个可选可不选)

  • 那么 A[i] 在这个子序列中是第 t+1 小

    根据公式:

  • 如果 A[i] 是第 1 小(t=0):系数 = 1

  • 如果 A[i] 是第 2 小(t=1):系数 = 1

  • 如果 A[i] 是第 j 小(j ≥ 3,即 t ≥ 2):系数 = 2^(j-2) = 2^(t-1)

后面元素的选择:不管前面选多少个,后面的 N-1-i 个元素都可以任意选择,方案数为 2^(N-1-i)

前面元素的选择: 从i个元素里面选t个(0<=t<=i),也就是C(i,t)

作为第1小(t=0):

方案数 = C(i, 0) × 2^(N-1-i) = 2^(N-1-i) 贡献 = A[i] × 2^(N-1-i)

作为第2小(t=1):

方案数 = C(i, 1) × 2^(N-1-i) = i × 2^(N-1-i) 贡献 = A[i] × i × 2^(N-1-i)

作为第 j≥3 小(t≥2):

方案数 = C(i, t) × 2^(N-1-i) 系数 = 2^(t-1) 贡献 = A[i] × 2^(N-1-i) × C(i, t) × 2^(t-1)

对所有 t ≥ 2 求和:

贡献 = A[i] × 2^(N-1-i) × Σ_{t=2}^i C(i, t) × 2^(t-1)通过二项式定理(a + b)^i = Σ_{t=0}^i C(i, t) × a^(i-t) × b^t,令 a=1, b=2:

(1 + 2)^i = Σ_{t=0}^i C(i, t) × 1^(i-t) × 2^t 3^i = Σ_{t=0}^i C(i, t) × 2^t即Σ_{t=0}^i C(i, t) × 2^t = 3^i

所以Σ_{t=2}^i C(i, t) × 2^t = 3^i – 1 – 2i,因为Σ_{t=2}^i C(i, t) × 2^t = (Σ_{t=0}^i C(i, t) × 2^t) – C(i,0)×2^0 – C(i,1)×2^1 = (Σ_{t=0}^i C(i, t) × 2^t) – 1 – 2i

最后化简得S = (1/2) × (3^i – 1 – 2i),那么位置i的总贡献=

A[i] × 2^(N-1-i) × [1 + i + (3^i – 1 – 2i)/2] (当 i ≥ 2)

对于 i < 2,需要单独处理:

  • i = 0:贡献 = A[0] × 2^(N-1)(只能作为第1小)

  • i = 1:贡献 = A[1] × [2^(N-2) + 1×2^(N-2)] = A[1] × 2^(N-1)(作为第1小和第2小)

接着遍历剩余位置求和即可

代码如下:

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 2e5 + 9;
using ll = long long;
const ll MOD = 998244353;

ll a[MAXN];

// 快速幂:计算 a^b % MOD
ll ksm(ll a, ll b)
{
ll res = 1;
while (b > 0)
{
if (b & 1)
res = res * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return res;
}

// 求逆元:inv(b) = b^(MOD-2) % MOD
ll inv(ll b)
{
return ksm(b, MOD – 2);
}

void solve()
{
int n;
cin >> n;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
}

sort(a + 1, a + 1 + n);

ll ans = 0;
ll inv2 = inv(2); // 2 的逆元

for (int i = 1; i <= n; i++)
{
ll coef; // 贡献系数

if (i == 1)
{
// 位置 1:只能作为第1小
// 贡献 = a[1] × 2^(n-1)
coef = ksm(2, n – 1);
}
else if (i == 2)
{
// 位置 2:可以作为第1小或第2小
// 贡献 = a[2] × [2^(n-2) + 1×2^(n-2)] = a[2] × 2^(n-1)
coef = ksm(2, n – 1);
}
else
{
// 位置 i >= 3:
// 贡献系数 = 2^(n-i) × [1 + (i-1) + sum3[i-1]]
// 其中 sum3[i-1] = (3^(i-1) – 1 – 2(i-1)) / 2

// 计算 3^(i-1)
ll pow3 = ksm(3, i – 1);

// 计算 sum3 = (3^(i-1) – 1 – 2(i-1)) / 2
ll sum3 = (pow3 – 1 – 2LL * (i – 1)) % MOD;
if (sum3 < 0)
sum3 += MOD;
sum3 = sum3 * inv2 % MOD; // 除以 2

// 计算 2^(n-i)
ll pow2 = ksm(2, n – i);

// 系数 = 2^(n-i) × [1 + (i-1) + sum3]
ll part = (1 + (i – 1) + sum3) % MOD;
coef = part * pow2 % MOD;
}

ans = (ans + coef * a[i]) % MOD;
}

cout << ans << "\\n";
}

int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);

int t;
cin >> t;
while (t–)
{
solve();
}

return 0;
}

赞(0)
未经允许不得转载:171主机测评 » The 2025 ICPC Asia East Continent Online Contest (II) D题(数学)
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址