题目 | Distance
2023牛客暑期多校训练营6
B - Distance
https://ac.nowcoder.com/acm/contest/57360/B
题意
给定长度为
题解
可以选择
对于一对大小为
其实不按照下标一一对应,也可以是代价一样最小的变换方式。但是按下标一一对应进行变换能够方便后续的计算,因此我们不妨设变换方式就是按照下标一一对应。
然后,该题思路是对于枚举每一对
考虑下面这个示例,被框住的数字是目前正在考虑的数字:
那么能让
- 左边选
个,右边选 个:长度为 ,选中数字处于下标 ,共 种。 - 左边选
个,右边选 个:长度为 ,选中数字处于下标 ,共 种。 - 左边选
个,右边选 个:长度为 ,选中数字处于下标 ,共 种。 - 左边选
个,右边选 个:长度为 ,选中数字处于下标 ,共 种。 - 左边选
个,右边选 个:长度为 ,选中数字处于下标 ,共 种。 - 左边选
个,右边选 个:长度为 ,选中数字处于下标 ,共 种。
共
接下来分析一下为什么是这么多。对于一对
那么选择的区间左侧最多放
(左右侧的计算是等价的,下面都只以右侧为例)那么右侧的选择数的情况有:
但上面只考虑了选择的方式,实际上还要考虑选出来的数怎么对应。例如上面这个例子,如果
因此,右侧的情况数应该是:
计算这个情况数的时间复杂度是
根据范德蒙德卷积公式:
它有推论:
这个推论正好和上面的情况数对应上了,于是情况数转化成:
这下就能在
预处理组合数后,时间复杂度为
代码
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
constexpr int MAXN = 4e3 + 10, MOD = 998244353;
int comb[MAXN][MAXN];
void init_comb()
{
for (int i = 0; i < MAXN; i++)
comb[i][0] = 1;
for (int i = 1; i < MAXN; i++)
for (int j = 1; j < MAXN; j++)
comb[i][j] = (comb[i - 1][j] + comb[i - 1][j - 1]) % MOD;
}
int n;
int s[MAXN], t[MAXN];
void solve()
{
cin >> n;
for (int i = 1; i <= n; i++)
cin >> s[i];
for (int i = 1; i <= n; i++)
cin >> t[i];
sort(s + 1, s + 1 + n);
sort(t + 1, t + 1 + n);
int ans = 0;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
int li = i - 1, lj = j - 1;
int ri = n - i, rj = n - j;
int lcnt = comb[li + lj][li];
int rcnt = comb[ri + rj][ri];
int delta = abs(s[i] - t[j]) % MOD;
ans = (ans + lcnt * rcnt % MOD * delta % MOD) % MOD;
}
}
cout << ans << endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
init_comb();
int t = 1;
// cin >> t;
while (t--)
solve();
return 0;
}
本文采用 CC BY-SA 4.0 许可,本文 Markdown 源码:Haotian-BiJi