文章目录
2019牛客暑期多校训练营(第一场)
A Equivalent Prefixes
题意:
给定长度相等的序列A,B,求最大的x,使得 A 1 , A 2 , . . . A x A_1,A_2,...A_x A1,A2,...Ax和 B 1 , B 2 , B 3 , . . . B x B_1,B_2,B_3,...B_x B1,B2,B3,...Bx建立的笛卡尔树相同,笛卡尔树是递归构造的,从整个序列出发,查找最小值作为根,然后将序列分成两个部分,分治构造
分析:
对两个序列都跑一遍单调栈,如果在每个位置单调栈的元素的数量都相同,那么建立的笛卡尔树肯定相同,找到最大的x即可
参考代码
https://ac.nowcoder.com/acm/contest/view-submission?submissionId=40901481
B Integration
题意:
给定
求
分析:
我们知道
1.
1
π
∫
0
∞
1
a
2
+
x
2
d
x
=
1
π
∗
a
∫
0
∞
1
1
+
(
x
/
a
)
2
d
(
x
a
)
=
1
(
2
∗
a
)
\frac{1}{\pi} \int_{ 0}^{\infty} \frac{1}{a^2+x^2}dx =\frac{1}{\pi*a} \int_{ 0}^{\infty} \frac{1}{1+(x/a)^2}d(\frac{x}{a}) = \frac{1}{(2*a)}
π1∫0∞a2+x21dx=π∗a1∫0∞1+(x/a)21d(ax)=(2∗a)1
2. 将连乘符号做分解,分成若干个上式相加,逐个算出积分就可以了
1
(
a
+
x
)
(
b
+
x
)
=
A
a
+
x
+
B
b
+
x
\frac{1}{(a+x)(b+x)} = \frac{A}{a+x}+\frac{B}{b+x}
(a+x)(b+x)1=a+xA+b+xB
关键是怎么求A,B,这就需要一点数学知识,对于等式两边同时乘以
(
a
+
x
)
∗
(
b
+
x
)
(a+x)*(b+x)
(a+x)∗(b+x),然后分别令
x
=
−
a
和
x
=
−
b
x = -a 和 x = -b
x=−a和x=−b就可以得到A,B,对于多个相乘同理,求出系数之后就可以计算了
参考代码
https://ac.nowcoder.com/acm/contest/view-submission?submissionId=40858470
C Euclidean Distance
题意:
找到一组
p
1
,
p
2
,
p
3
,
.
.
.
p
n
p_1,p_2,p_3,...p_n
p1,p2,p3,...pn满足
使得
∑
i
=
1
i
=
n
(
a
i
/
m
−
p
i
)
\sum_{i=1}^{i= n}{(a_i/m-p_i)}
∑i=1i=n(ai/m−pi)最小
分析:
先对
a
i
a_i
ai 从大到小排序,所有的
p
i
p_i
pi 相加等于1,提出来一个
1
/
(
m
2
)
1/(m^2)
1/(m2),相当于将m分配到这n个
a
i
a_i
ai中去使得他们的平方和最小
我们想一个贪心策略,很明显
if a_i > a_j
我们有x要减去
从a_i 中扣除
有 sum_1 = (a_i-x)^2+a_j^2 = a_i^2+a_j^2-2x*a_i+x^2
从a_j 中扣除
有 sum_2 = a_i^2+(a_j-x)^2 = a_i^2+a_j^2-2x*a_j+x^2
很明显
sum_1 <= sum_2
于是贪心策略就是从大的中扣除,直到和第二大相同,然后再削减
参考
https://blog.nowcoder.net/n/1539da6d6d6e47a6998b5c6f5bba2167
D Parity of Tuples
https://ac.nowcoder.com/discuss/208861?type=101&order=0&pos=1&page=1
E ABBA
题意:
对于一个只有 AB字符组成的长度为 2*(n+m) 的字符串,要求其中存在AB子序列n个,BA子序列m个,给定n,m问存在多少中方法?
分析:
我们知道序列到某一个位置的时候有一个限制,是A的个数不能超过B个,B的个数不能超过Am个,其他情况都是合法的。
参考代码:
const int maxn = 2e3 + 10;
LL dp[maxn][maxn];
int main(void)
{
LL n, m;
while (cin >> n >> m) {
for (int i = 0; i <= n + m; ++i) {
for (int j = 0; j <= n + m; ++j) {
dp[i][j] = 0;
}
}
dp[0][0] = 1;
for (int i = 0; i <= n + m; ++i) {
for (int j = 0; j <= n + m; ++j) {
if (i - j < n)
(dp[i + 1][j] += dp[i][j]) %= mod;
if (j - i < m)
(dp[i][j + 1] += dp[i][j]) %= mod;
}
}
printf("%lld\n", dp[n + m][n + m]);
}
return 0;
}
F Random Point in Triangle
11/36
我们可以直接出来随出来一个三角形,然后跑随机看是36分之几
G Substrings 2
题意:
计算 所有的满足异或和为0的所有集合的元素个数的和
分析:
计算集合的元素个数之和可以改成求所有的元素的贡献来做。
考虑线性基,我们先对所有n个元素的元素求线性基
- 线性基外的元素的贡献是 2 n − r − 1 2^{n-r-1} 2n−r−1, r 是线性基中元素的个数,也就是基底的个数,为什么是 2 n − r − 1 2^{n-r-1} 2n−r−1呢?因为考虑线性基外的元素a,我们选取a,除线性基中元素剩下 n-r-1个元素,这n-r-1个元素可以选择取或者不取,有 2 n − r − 1 2^{n-r-1} 2n−r−1中组合,这些组合和a的异或一定可以由线性基中若干个元素组合而成,所以排列数位 2 n − r − 1 2^{n-r-1} 2n−r−1
- 对于线性基中的元素a,我们考虑将剩下的 n − r n-r n−r的元素建立一个线性基B,每次添加除a以外原线性基中的元素r-1个,如果a可以由这个新线性基表示出来,那么同样它的贡献也是 2 n − r − 1 2^{n-r-1} 2n−r−1, 因为新的线性基也可以组成所有的元素,如果不能表示出来,说明这个元素不能添加进入任何集合。
const int MN = 62;
LL A[MN], B[MN], C[MN];
bool Ins(LL x, LL *a) {
for (int i = MN - 1; i >= 0; --i) {
if (x & (1LL << i)) {
if (!a[i])
{
a[i] = x;
return true;
}
else
x ^= a[i];
}
}
return false;
}
const int maxn = 1e5 + 10;
LL pow2[maxn];
LL a[maxn];
int main() {
pow2[0] = 1;
for (int i = 1; i < maxn; ++i)
pow2[i] = pow2[i - 1] * 2 % mod;
// cout << pow2[10] << endl;
int n;
while (~scanf("%d", &n)) {
me(A), me(B);
for (int i = 1; i <= n; ++i)
scanf("%lld", &a[i]);
vector<LL> v;
for (int i = 1; i <= n; ++i) {
if (!Ins(a[i], A))
Ins(a[i], B);
else
v.Pb(a[i]);
}
int cnt = 0;
for (int i = 0; i < MN; ++i)
if (A[i] != 0)
cnt++;
if (cnt == n) {
puts("0");
continue;
}
LL ans = 0;
// cout << " r = " << cnt << endl;
ans = n - cnt;
for (auto c : v) {
memcpy(C, B, sizeof(C));
for (auto c2 : v) {
if (c == c2) continue;
Ins(c2, C);
}
// cout << c << " " << Ins(c, C) << endl;
if (!Ins(c, C))
ans++;
}
// cout << " ans = " << ans << endl;
printf("%lld\n", ans * pow2[n - cnt - 1] % mod);
}
return 0;
}
/*
2
1000000000000000000 1000000000000000000
*/
I
https://blog.nowcoder.net/n/7205418146f3446eb0b1ecec8d2ab1da