T1

100%

用循环语句输入 AiA_i 的时候判断一下是否等于 xx,如果 Ai=xA_i=x 答案就增加 11

注意数据范围,xxAiA_i 应使用 long long\text{long long} 类型的变量来读入和处理。

时间复杂度 O(n)O(n)

T2

100%

两重循环,外层循环枚举数组第 ii 项,内层循环计算 AiA_ikk 次幂。

注意取模,计算其中一项 kk 次幂的过程中也可能爆 int\text{int}

时间复杂度 O(nk)O(nk)

T3

50%

V=min(a,b)V=\min(a,b)

直接从 11VV 枚举 xx,如果 xxaabb 的公因数,答案就增加 xx

时间复杂度 O(V)O(V)

60%

对于测试点#6,因为 a=ba=b,所以 aabb 的公因数等价于 aa 的因数,找出 aa 的所有因数再加起来就是答案了。

aa 的因数时, xx 只需要枚举到 a\sqrt{a},如果 xxaa 的因数那么 ax\frac{a}{x} 也是 aa 的因数。注意判断 x=axx=\frac{a}{x} 的情况,不要加重复了。

时间复杂度 O(a)O(\sqrt {a})

结合第一部分可以拿到 60%60\% 的分数。

100%

先求出 aabb 的公因数 c=gcd(a,b)c=\gcd(a,b)aabb 的公因数等价于 cc 的因数。显然 cVc\leq V

cc 的因数时,同样只需要枚举到 c\sqrt{c}

时间复杂度 O(V)O(\sqrt {V})

T4

30%

假设 a,b,ca,b,c 三根木棍的长度满足 lenalenblenclen_a\leq len_b\leq len_c,那么当且仅当 lena+lenb>lenclen_a+len_b>len_c 时这三根木棍可以搭成面积大于 00 的三角形。

直接三重循环枚举三根木棍,用上述规则进行判断,符合则答案增加 11

注意三根木棍编号不能相同,还要避免重复枚举同一个方案。

时间复杂度 O(n3)O(n^3)

50%

将木棍按照长度从短到长排序。

先用两重循环枚举更短的两根木棍 aabb (a<ba<b),那么只要 lenc<lena+lenblen_c<len_a+len_b 就可以了,用二分法求出共有多少根木棍可以和 a,ba,b 一起搭成面积大于 00 的三角形。

要避免重复枚举同一方案,所以只有满足 c>bc>b 才是可选的 cc

时间复杂度 O(n2log(n))O(n^2\log(n))

70%

对于测试点#6~7,预处理长度不超过 xx 的木棍数量为 sum[x]sum[x]

用两重循环枚举 aabb 之后,可选的 cc 的数量就等于sum[lena+lenb1]bsum[len_a+len_b-1]-b

注意虽然 lenlen 的范围是 10610^6,但是 lena+lenblen_a+len_b 有可能达到 2×1062\times 10^6,所以预处理 sumsum 数组时要预处理到 2×1062\times 10^6,或者特判 lena+lenb>106len_a+len_b>10^6 的情况。

lenilen_i 的最大值为 L=max{leni}L=\max\{len_i\}

时间复杂度 O(L+n2)O(L+n^2)

结合第二部分可以拿到 70%70\% 的分数。

100%

aa 不变时,随着 bb 的增大, lena+lenblen_a+len_b 也是增大的。

所以在木棍按长度排序之后,我们可以把 bbcc 看成双指针,当 bb 右移时,尽量右移 cc 直到 c=nc=n 或者 lena+lenblenc+1len_a+len_b\leq len_{c+1} 时停下。

相当于在第二部分的基础上,用双指针代替二分法,来求出有多少根木棍可以作为 cc

时间复杂度 O(n2)O(n^2)

T5

20%

枚举每个知识点学与不学,那么共有 2n2^n 个不同的方案,然后 O(n)O(n) 判断方案中每个选择学的知识点是否满足前置知识点都学习了,用合法方案的价值和更新答案。

时间复杂度 O(2nn)O(2^nn)

60%

因为每个知识点最多只会有一个前置知识点,可以把这类前置关系看成树的结构,pip_iii 的父节点。

dp[i][j]dp[i][j] 表示以 ii 为根的子树中,学 jj 个知识点的最大价值。我们枚举节点 xx 的子节点 yy,用 tmp[x][i]tmp[x][i] 表示以 xx 为根的子树已经处理过的部分(即不包括 yy 等未处理的子节点和以它们为根的子树)中,学 ii 个知识点的最大价值。那么 tmp[x][a+b]=max{tmp[x][a]+dp[y][b]}tmp[x][a+b]=\max\{tmp[x][a]+dp[y][b]\},这里 aa 至少是 11,因为不学知识点 xx 就无法学习子树内其他知识点。

由于可能存在多个 pi=0p_i=0 的知识点,可以把 00 看成树的根,那么答案就是 dp[0][m+1]dp[0][m+1]

实际实现中,tmptmpdpdp 可以是同一个数组,原理同01背包的一维写法,此时需要按 a+ba+b 从大到小的顺序更新,记 s=a+bs=a+b,参考代码如下:

for (int s = m + 1; s >= 1; s--)
	for (int b = 1; b < s; b++) {
		int a = s - b;
		dp[x][s] = max(dp[x][s], dp[x][a] + dp[y][b]);
	}

时间复杂度 O(n3)O(n^3)

100%

siz[i]siz[i] 表示以 ii 为根的子树中知识点数量, tmpsiz[i]tmpsiz[i] 表示以 ii 为根的子树已经处理过的部分中知识点的数量。

如果限制 atmpsiz[x]a\leq tmpsiz[x]bsiz[y]b\leq siz[y],可以证明总复杂度会降低到 O(n2)O(n^2)

这一过程的复杂度等价于在两个部分各选一个点的方案数,不难发现任意一对点在这个过程中只会在LCA(最近公共祖先)处被考虑一次,所以总复杂度是 O(n2)O(n^2)

如下图,点对 (p,q)(p,q) 仅在 LCA(p,q)=xLCA(p,q)=x 时被考虑,其中黄色点是以 xx 为根的子树已经处理过的部分,绿色点是以 yy 为根的子树。

参考代码如下:

for (int s = siz[x] + siz[y]; s >= 1; s--) {
	for (int b = max(s - siz[x], 0); b <= siz[y] && b < s; b++) {
        int a = s - b;
		dp[x][s] = max(dp[x][s], dp[x][a] + dp[y][b]);
	}

时间复杂度 O(n2)O(n^2)

T6

10%

三重循环,外层两重循环枚举子区间 [l,r][l,r],内层再用一重循环求出区间和 sumA(l,r)=i=lrAisumA(l,r)=\sum_{i=l}^{r} A_i,如果满足 avg(l,r)xavg(l,r)\geq x 的条件就把区间和加到答案上。

注意取模。

可以不计算平均值,用区间和直接与 x×(rl+1)x\times (r-l+1) 进行比较。

时间复杂度 O(n3)O(n^3)

30%

预处理前缀和,就可以 O(1)O(1) 计算区间和。这样只需要两重循环枚举子区间。

时间复杂度 O(n2)O(n^2)

50%

处理出数组 Bi=AixB_i=A_i-x,记 BiB_i 的区间和为 sumB(l,r)=i=lrBisumB(l,r)=\sum_{i=l}^{r} B_i,那么子区间 [l,r][l,r] 满足条件等价于 sumB(l,r)0sumB(l,r)\geq 0

枚举子区间右端点 rr,对于满足 sumB(l,r)0sumB(l,r)\geq 0 的每一个左端点 ll,答案增加 sumA(l,r)sumA(l,r),这个做法和第二部分类似。

在这个基础上,把 sumA(l,r)sumA(l,r) 分解为 sumA(1,r)sumA(1,r)sumA(1,l1)-sumA(1,l-1) 两部分。

sumB(l,r)0sumB(l,r)\geq 0 也可以转化为 sumB(1,r)sumB(1,l1)sumB(1,r)\geq sumB(1,l-1),称为对于 rr 合法的 ll

那么第一部分对答案贡献的次数为对于 rr 合法的 ll 的数量。

第二部分对答案的总贡献为每个对于 rr 合法的 ll 都让答案增加 sumA(1,l1)-sumA(1,l-1)

BiB_i 的前缀和的值作为下标,用权值线段树分别维护 sumB(1,i)=jsumB(1,i)=j 对应的 ii 的数量以及对应的 sumA(1,i1)\sum sumA(1,i-1),就可以枚举 rr,分别计算以上两部分了。

BiB_i 的前缀和的跨度为 V=max{sumB(1,i)}min{sumB(1,i)}V=\max\{sumB(1,i)\}-\min\{sumB(1,i)\}

时间复杂度 O(nlog(V))O(n\log(V))

结合第二部分可以拿到 50%50\% 的分数。

60%

对于测试点#6,因为 xmin{Ai}x\leq \min\{A_i\},所以每个区间都满足条件。

答案就等于所有子区间的区间和之和。

时间复杂度 O(n)O(n)

结合第二、第三部分可以拿到 60%60\% 的分数。

100%

在第三部分的基础上,将下标域扩展到 [1012,1012][-10^{12},10^{12}]

  • 方法1:

使用动态开点的权值线段树。

时间复杂度 O(nlog(V))O(n\log(V))

  • 方法2:

计算出 BiB_i 的所有前缀和之后,进行离散化,然后以离散化后的权值为下标建线段树。

时间复杂度 O(nlog(n))O(n\log(n))

0 comments

No comments so far...