2021牛客暑期多校训练营5
B、Boxes
果然赛场上碰到概率就裂了。
第一种情况就是不问,即 Σ w [ i ] \Sigma w[i] Σw[i]。
第二种情况需要询问,先加上 C C C。之后枚举需要问几个才能确定,答案为 C + Σ p r e [ i ] ∗ ( 1 2 ) n − i C+\Sigma pre[i]*(\frac{1}{2})^{n-i} C+Σpre[i]∗(21)n−i。
取最小值输出即可。
#include <bits/stdc++.h>
typedef long long ll;
const int MAXN = 1e5 + 10;
double w[MAXN], C, pre[MAXN];
int n;
int main()
{
scanf("%d%lf", &n, &C);
for (int i = 1; i <= n; ++i)
scanf("%lf", &w[i]);
std::sort(w + 1, w + 1 + n);
for (int i = 1; i <= n; ++i)
pre[i] = pre[i - 1] + w[i];
double p = 0.5, ans = C;
for (int i = n - 1; i >= 1; --i, p *= 0.5)
ans += p * pre[i];
printf("%.10lf\n", std::min(ans, pre[n]));
return 0;
}
D、Double Strings
d p 1 [ i ] [ j ] dp1[i][j] dp1[i][j]: A A A串前 i i i个字母与 B B B串前 j j j个字母的等长公共子序列个数(包括空串)
d p 1 [ i ] [ j ] = d p 1 [ i − 1 ] [ j ] + d p 1 [ i ] [ j − 1 ] − d p 1 [ i − 1 ] [ j − 1 ] [ A [ i ] ≠ B [ j ] ] dp1[i][j]=dp1[i-1][j]+dp1[i][j-1]-dp1[i-1][j-1][A[i]\not =B[j]] dp1[i][j]=dp1[i−1][j]+dp1[i][j−1]−dp1[i−1][j−1][A[i]=B[j]]
d p 2 [ i ] [ j ] dp2[i][j] dp2[i][j]: A A A串前 i i i个字母与 B B B串前 j j j个字母中选择等长的公共子序列并满足 A A A串的子序列字典序小于 B B B串子序列字典序的子序列个数
d p 2 [ i ] [ j ] = d p 2 [ i − 1 ] [ j ] + d p 2 [ i ] [ j − 1 ] + d p 1 [ i − 1 ] [ j − 1 ] [ A [ i ] < B [ j ] ] dp2[i][j]=dp2[i-1][j]+dp2[i][j-1]+dp1[i-1][j-1][A[i]<B[j]] dp2[i][j]=dp2[i−1][j]+dp2[i][j−1]+dp1[i−1][j−1][A[i]<B[j]]
转移即可。注意 d p 1 dp1 dp1的初始化。
#include <bits/stdc++.h>
typedef long long ll;
const int MAXN = 5e3 + 10, MOD = 1e9 + 7;
int dp1[MAXN][MAXN], dp2[MAXN][MAXN];
char a[MAXN], b[MAXN];
int main()
{
scanf("%s%s", a + 1, b + 1);
int n = strlen(a + 1), m = strlen(b + 1);
for (int i = 0; i <= m; ++i)
dp1[0][i] = 1;
for (int i = 0; i <= n; ++i)
dp1[i][0] = 1;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
{
dp1[i][j] = ((dp1[i - 1][j] + dp1[i][j - 1] - dp1[i - 1][j - 1]) % MOD + MOD) % MOD;
if (a[i] == b[j]) dp1[i][j] = (dp1[i][j] + dp1[i - 1][j - 1]) % MOD;
}
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
{
dp2[i][j] = (dp2[i - 1][j] + dp2[i][j - 1]) % MOD;
if (a[i] < b[j]) dp2[i][j] = (dp2[i][j] + dp1[i - 1][j - 1]) % MOD;
}
printf("%d\n", dp2[n][m]);
return 0;
}
H、Holding Two
构造如下矩阵即可。
011001100110011…
100110011001100…
011001100110011…
100110011001100…
…
#include <bits/stdc++.h>
typedef long long ll;
int main()
{
int n, m; scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
if ((j / 2) & 1) printf("%d", 0 ^ (i & 1));
else printf("%d", 1 ^ (i & 1));
}
printf("\n");
}
return 0;
}
K、King of Range
枚举左端点 l l l。若当 r = i r=i r=i时已满足 m a x − m i n > k max-min>k max−min>k,则从 i i i开始到 n n n的区间均满足。(因为最大值不减)
于是双指针计算第一个满足条件的右端点,累加答案即可。
#include <bits/stdc++.h>
typedef long long ll;
const int MAXN = 1e5 + 10;
int a[MAXN], que1[MAXN], que2[MAXN];
int main()
{
int n, m; scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i)
scanf("%d", &a[i]);
while (m--)
{
int k; scanf("%d", &k);
int l1 = 0, r1 = 0, l2 = 0, r2 = 0;
que1[0] = que2[0] = 1;
ll ans = 0;
for (int i = 1, j = 1; i <= n; ++i)
{
if (l1 <= r1 && que1[l1] < i) ++l1;
if (l2 <= r2 && que2[l2] < i) ++l2;
while (j + 1 <= n && a[que2[l2]] - a[que1[l1]] <= k)
{
++j;
while (l2 <= r2 && a[que2[r2]] <= a[j]) --r2;
que2[++r2] = j;
while (l1 <= r1 && a[que1[r1]] >= a[j]) --r1;
que1[++r1] = j;
}
if (a[que2[l2]] - a[que1[l1]] > k) ans += n - j + 1;
}
printf("%lld\n", ans);
}
return 0;
}