P10090 [ROIR 2022] 幼儿园的新年 (Day 2) 题解
P10090 [ROIR 2022] 幼儿园的新年 (Day 2) 题解
设 \(kn(k\in\mathbb{N}_+)\) 为 \(n\) 的倍数。
首先,我们确定 \(kn\) 的取值范围,显然 \(kn\le a+b\)。
此时 \(kn\) 的枚举范围已经确定,然后该考虑什么样的 \((x,y)\) 的可以对答案产生贡献。不难发现 \((x,y)\) 的取法受到 \(a,b\) 与 \(n\) 之间大小关系的影响,接下来我们便具体探讨其中的关系。
以下若无特殊说明,默认 \(a\le b,0\le x\le a,0\le y\le b\)。
先从简单的入手,只考虑单个 \(kn\) 对答案的贡献,我们可分为以下几种情况:
- \(kn\le a,b\)
由于 \(kn\le a,b\),则必然有 \(x\) 或 \(y\) 满足 \(x=kn\) 或 \(y=kn\),便有以下几种可能:\[\begin{aligned} 0+y&=kn\\ 1+(y-1)&=kn\\ &\vdots\\ x+0&=kn \end{aligned} \]那么此时便对答案有 \((x-0)+1=(y-0)+1=kn+1\) 的贡献。 - \(a<kn\le b\)
由于此时 \(a<kn\),所以无论 \(x\) 怎么取,仍然不会超出 \(kn\) 的范围,那么 \(x\) 的范围便固定在 \([0,a]\) 中,那么 \(y\) 的范围也随之固定,也就有以下几种可能:\[\begin{aligned} 0+y&=kn\\ 1+(y-1)&=kn\\ &\vdots\\ a+(y-a)&=kn \end{aligned} \]那么此时对答案有 \((a-0)+1=a+1\) 的贡献。 - \(a,b<kn\)
同理,请自己尝试像上面两种情况推导后,得出以下几种可能:\[\begin{aligned} (kn-b)+b&=kn\\ (kn-b+1)+(b-1)&=kn\\ &\vdots\\ a+(kn-a)&=kn \end{aligned} \]那么此时对答案有 \(a-(kn-b)+1=a+b-kn+1\) 的贡献。
此时我们对单个 \(kn\) 考虑完毕,再考虑多个 \(kn\) 对答案的贡献。
现在的变量又多了一个 \(k\),由于 \(k\) 的变化导致 \(kn\) 与 \(a,b\) 的大小关系不定,所以我们要确定好在上面三种情况中 \(k\) 各自的取值范围。
-
\(kn\le a,b\)
令 \(m_1=\left\lfloor\frac{a}{n}\right\rfloor\),则 \(k\in[1,m_1]\) 总的贡献为:\[\sum_{k=1}^{m_1}\left(i\times n+1\right)=\sum_{k=1}^{m_1}(i\times n)+m_1 \]利用求和公式即可化简为:
\[\frac{n(m_1+1)\times m_1}{2}+m_1 \] -
\(a<kn\le b\)
令 \(m_2=\left\lfloor\frac{b}{n}\right\rfloor\),则 \(k\in(m_1,m_2]\)。不难发现,此条件下 \(k\) 的变化对最终贡献没有影响,所以贡献为:
\[\sum_{i=m_1+1}^{m_2}a+1=(m_2-m_1)\times(a+1) \] -
\(a,b<kn\)
令 \(m_3=\left\lfloor\frac{a+b}{n}\right\rfloor\),则 \(k\in(m_2,m_3]\),贡献为:\[\begin{aligned} &\sum_{i=m_2+1}^{m_3}(a+b-i\times n+1)\\ =&(m_3-m_2)\times(a+b+1)-\sum_{i=m_2+1}^{m_3}(i\times n)\\ =&(m_3-m_2)\times(a+b+1)-\left(\sum_{i=1}^{m_3}(i\times n)-\sum_{i=1}^{m_2}(i\times n)\right)\\ =&(m_3-m_2)\times(a+b+1)-\left(\frac{n(m_2+1)\times m_2}{2}-\frac{n(m_3+1)\times m_3}{2}\right) \end{aligned} \]
这样,我们就得出了最终的公式,用代码实现即可,时间复杂度 \(\mathcal{O}(t)\)
代码
$\text{Code}$
#include <bits/stdc++.h>
using namespace std;
int t, n, a, b, m1, m2, m3;
long long ans; // 别忘了 long long
template <typename type>
void read(type &res) {
type x = 0, f = 1;
char c = getchar();
for (; c < 48 || c > 57; c = getchar()) if (c == '-') f = ~f + 1;
for (; c > 47 && c < 58; c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
res = f * x;
}
int main() {
read(t);
while (t--) {
ans = 0;
read(n), read(a), read(b);
// 把上面的公式翻译成代码就行了
if (a > b) swap(a, b);
m1 = a / n;
m2 = b / n;
m3 = (a + b) / n;
// 下面也要开 long long
ans += ((1ll * n * (m1 + 1) * m1) >> 1) + m1;
ans += 1ll * (m2 - m1) * (a + 1);
ans += 1ll * (m3 - m2) * (a + b + 1) - (((1ll * n * (m3 + 1) * m3) >> 1) - ((1ll * n * (m2 + 1) * m2) >> 1));
printf("%lld\n", ans);
}
return 0;
}

浙公网安备 33010602011771号