链接:https://ac.nowcoder.com/acm/contest/74362
E-小红的子集取反
思路
线性dp,定义
d
p
i
,
j
dp_{i,j}
dpi,j表示使得数组前
i
i
i项元素和为
j
j
j的最小取反次数,初始状态
d
p
0
,
0
=
0
dp_{0,0}=0
dp0,0=0,转移方程:
d
p
i
,
j
=
m
i
n
(
d
p
i
−
1
,
j
+
a
i
,
d
p
i
−
1
,
j
+
(
−
a
i
)
+
1
)
dp_{i,j}=min(dp_{i-1,j+a_i},dp_{i-1,j+(-a_i)}+1)
dpi,j=min(dpi−1,j+ai,dpi−1,j+(−ai)+1)
注意
a
i
a_i
ai的和可能为负数,所以需要在
d
p
dp
dp数组中使用偏移量,这里偏移量取
40000
40000
40000。
代码
#include <bits/stdc++.h>
using namespace std;
int n, a;
int main() {
ios::sync_with_stdio(false);
cin >> n;
vector<vector<int>> dp(n + 1, vector<int>(8e4 + 1, n + 1));
int maxs = 40000;
dp[0][0 + maxs] = 0;
for (int i = 1; i <= n; i++) {
cin >> a;
for (int j = -maxs; j <= maxs; j++) {
if (-maxs <= j + a && j + a <= maxs) {
dp[i][j + maxs] = min(dp[i][j + maxs], dp[i - 1][j + a + maxs]);
}
if (-maxs <= j - a && j - a <= maxs) {
dp[i][j + maxs] = min(dp[i][j + maxs], dp[i - 1][j - a + maxs] + 1);
}
}
}
if (dp[n][0 + maxs] == n + 1) {
cout << "-1\n";
} else {
cout << dp[n][0 + maxs] << '\n';
}
return 0;
}
F-小红的连续段
思路
数学题,对于连续段数量恰好为 i i i的字符串,有两种情况:
- 字符’a’的连续串有 ⌊ i 2 ⌋ \lfloor\frac{i}{2}\rfloor ⌊2i⌋个,字符’b’的连续串有 ⌊ i + 1 2 ⌋ \lfloor\frac{i+1}{2}\rfloor ⌊2i+1⌋个
- 字符’a’的连续串有 ⌊ i + 1 2 ⌋ \lfloor\frac{i+1}{2}\rfloor ⌊2i+1⌋个,字符’b’的连续串有 ⌊ i 2 ⌋ \lfloor\frac{i}{2}\rfloor ⌊2i⌋个
记字符’a’的连续串数量为 a a a,字符’b’的连续串数量为 b b b,则根据隔板法和乘法原理,有 ( x − 1 a − 1 ) ( y − 1 b − 1 ) \dbinom{x-1}{a-1}\dbinom{y-1}{b-1} (a−1x−1)(b−1y−1)种情况。
代码
#include <bits/stdc++.h>
using namespace std;
const int MOD = 1e9 + 7;
int x, y;
long long f[1005], invf[1005];
long long qpow(long long a, int b) {
long long ans = 1;
while (b) {
if (b & 1) {
ans = ans * a % MOD;
}
a = a * a % MOD;
b >>= 1;
}
return ans;
}
long long C(int a, int b) { return f[a] * invf[b] % MOD * invf[a - b] % MOD; }
int main() {
ios::sync_with_stdio(false);
cin >> x >> y;
f[0] = f[1] = invf[0] = invf[1] = 1;
for (int i = 2; i <= 1000; i++) {
f[i] = f[i - 1] * i % MOD;
invf[i] = qpow(f[i], MOD - 2);
}
for (int i = 1; i <= x + y; i++) {
long long ans = 0;
int a = i / 2, b = (i + 1) / 2;
if (1 <= a && a <= x && 1 <= b && b <= y) {
ans = (ans + C(x - 1, a - 1) * C(y - 1, b - 1) % MOD) % MOD;
}
a = (i + 1) / 2, b = i / 2;
if (1 <= a && a <= x && 1 <= b && b <= y) {
ans = (ans + C(x - 1, a - 1) * C(y - 1, b - 1) % MOD) % MOD;
}
cout << ans << '\n';
}
return 0;
}