2023.6.17 每日一题
原题链接
A: Codeforces Round 572 (Div. 1) - C
B: Codeforces Round 691 (Div. 1) - A
A. Array Beauty - 2500
题目大意
定义一个数组 \(a\) 的美丽值为 :
\[\min_{1\le i<j\le n} |a_i - a_j|
\]
现在要求长度为 \(k\) 的所有子序列的美丽值之和。
解题思路
参考了dyh大爹的代码
首先鉴于一个子序列的美丽值的上界一定是 \(\frac{\max{a_i}}{k - 1}\),我们可以直接枚举每一种可能的美丽值,然后去找这种美丽值在多少子序列中出现。那么我们处理大于枚举值的子序列种类数,使用dp和一个前缀和数组表示,转移方程是从上一个选择的数迁移到新的数,使用一个双指针优化。每次枚举完成后将结果统计起来就可以得到答案了。
AC Code
#include <iostream>
#include <algorithm>
#include <cstring>
#include <numeric>
#define endl '\n'
#define ios ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr)
using namespace std;
typedef long long LL;
const int N = 1010;
const int MOD = 998244353;
int a[N];
LL dp[N][N], s[N][N];
void solve() {
LL res = 0;
int n, k;
cin >> n >> k;
for (int i = 1; i <= n; ++i) {
cin >> a[i];
}
sort(a + 1, a + n + 1);
for (int i = 1; i <= (100010) / (k - 1); ++i) {
for (int j = 1; j <= n + 1; ++j) {
for (int l = 1; l <= k + 1; ++l) {
dp[j][l] = 0;
s[j][l] = 0;
}
}
int cnt = 1;
dp[1][1] = s[1][1] = 1;
for (int j = 2; j <= n + 1; ++j) {
while (cnt + 1 < j && a[j - 1] - a[cnt] >= i) cnt++;
for (int l = 2; l <= k + 1; ++l) {
dp[j][l] = s[cnt][l - 1];
}
for (int l = 1; l <= k + 1; ++l) {
s[j][l] = (dp[j][l] + s[j - 1][l]) % MOD;
}
}
res = (res + s[n + 1][k + 1]) % MOD;
}
cout << res << endl;
}
signed main() {
ios;
int T = 1;
// cin >> T;
while (T--) {
solve();
}
}
B. Row GCD - 1600
题目大意
给定两列大正数 \(a_1,\dots, a_n\) 和 \(b_1,\dots,b_m\),现在要求 \(a_1 + b_j, \dots, a_n + b_j\) 的最大公约数。
解题思路
暴力一个个找不TLE才怪了,我们需要找到每次运算的公共特征。
我们知道对于gcd有如下性质:
\[\gcd(a,\ b) = \gcd(a,\ b - a)
\]
这是我们欧几里得算法成立的重要条件。
那么对我们求的式子处理,就得到:
\[\begin{aligned}
&\gcd(a_1 + b_j,\ a_2 + b_j,\dots,\ a_n + b_j)\\
=&\gcd(a_1 + b_j,\ a_2 - a_1,\dots,\ a_n - a_1)\\
=&\gcd(a_1 + b_j, gcd\_)
\end{aligned}
\]
这里的 \(gcd\_\) 是恒定值,可以在读入 \(a\) 数列时得到,那么只需要保留一个 \(a_1\) 的值,其他值在读入时优化掉即可。
AC Code
#include <iostream>
#include <algorithm>
#include <cstring>
#include <numeric>
#define endl '\n'
#define ios ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr)
using namespace std;
typedef long long LL;
const int N = 3e5 + 10;
const int MOD = 1e9 + 7;
void solve() {
int n, m;
cin >> n >> m;
n--;
LL a;
cin >> a;
LL gcd_ = 0;
while (n--) {
LL x;
cin >> x;
gcd_ = gcd(gcd_, x - a);
}
gcd_ = abs(gcd_);
while (m--) {
LL x;
cin >> x;
cout << gcd(gcd_, a + x) << ' ';
}
cout << endl;
}
signed main() {
ios;
int T = 1;
// cin >> T;
while (T--) {
solve();
}
}