博客园同步
原题链接
简要题意:
给定 n , m n,m n,m,求:
∑ i = 1 n ∑ j = 1 m ( n mod i ) × ( m mod j ) , i ≠ j \sum_{i=1}^n \sum_{j=1}^m (n \space \text{mod} \space i) \times (m \space \text{mod} \space j) , i \not = j i=1∑nj=1∑m(n mod i)×(m mod j),i=j
n , m ≤ 1 0 9 n,m \leq 10^9 n,m≤109.
我们直接奔着 100 100 100 分的数据去吧,不要看部分分,部分分就没意思。
这个式子的瓶颈在于 n mod i n \space \text{mod} \space i n mod i 的展开问题。所以只需要用 n mod i = n − ⌊ n i ⌋ × i n \space \text{mod} \space i = n - \lfloor \frac{n}{i} \rfloor \times i n mod i=n−⌊in⌋×i ,然后灵活用多项式的拆开与合并,一波整除分块带走即可。
首先说好,这一次的推式子没有 莫比乌斯反演,也没有 奇怪的筛法,有的只是 多项式的灵活展开 与 整除分块。
于是我们开始推式子。
∑ i = 1 n ∑ j = 1 m ( n mod i ) × ( m mod j ) , i ≠ j \sum_{i=1}^n \sum_{j=1}^m (n \space \text{mod} \space i) \times (m \space \text{mod} \space j) , i \not = j i=1∑nj=1∑m(n mod i)×(m mod j),i=j
= ∑ i = 1 n ∑ j = 1 m ( n − ⌊ n i ⌋ × i ) × ( m − ⌊ m j ⌋ × j ) , i ≠ j = \sum_{i=1}^n \sum_{j=1}^m (n - \lfloor \frac{n}{i} \rfloor \times i) \times (m - \lfloor \frac{m}{j} \rfloor \times j) , i \not = j =i=1∑nj=1∑m(n−⌊in⌋×i)×(m−⌊jm⌋×j),i=j
= ∑ i = 1 n ( n − ⌊ n i ⌋ × i ) × ∑ j = 1 m ( m − ⌊ m j ⌋ × j ) , i ≠ j = \sum_{i=1}^n (n - \lfloor \frac{n}{i} \rfloor \times i) \times \sum_{j=1}^m (m - \lfloor \frac{m}{j} \rfloor \times j) , i \not = j =i=1∑n(n−⌊in⌋×i)×j=1∑m(m−⌊jm⌋×j),i=j
首先我们把 i = j i=j i=j 的答案丢掉,先做所有的答案。
令 f n = ∑ i = 1 n ( n − ⌊ n i ⌋ × i ) f_n = \sum_{i=1}^n (n - \lfloor \frac{n}{i} \rfloor \times i) fn=∑i=1n(n−⌊in⌋×i),则 ans = f n × f m \text{ans} = f_n \times f_m ans=fn×fm,考虑如何快速求 f f f.
f n = ∑ i = 1 n ( n − ⌊ n i ⌋ × i ) f_n = \sum_{i=1}^n (n - \lfloor \frac{n}{i} \rfloor \times i) fn=i=1∑n(n−⌊in⌋×i)
= n 2 − ∑ i = 1 n ( ⌊ n i ⌋ × i ) = n^2 - \sum_{i=1}^n \Big( \lfloor \frac{n}{i} \rfloor \times i \Big) =n2−i=1∑n(⌊in⌋×i)
然后你会发现这东西直接 整除分块, O ( n ) \mathcal{O}( \sqrt{n}) O(n) 很稳。
最后多余的 i = j i=j i=j 的答案应该会是:
∑ i = 1 min ( n , m ) ( n mod i ) × ( m mod i ) \sum_{i=1}^{\min(n,m)} (n \space \text{mod} \space i) \times (m \space \text{mod} \space i) i=1∑min(n,m)(n mod i)×(m mod i)
= ∑ i = 1 min ( n , m ) ( n − ⌊ n i ⌋ × i ) × ( m − ⌊ m i ⌋ × i ) = \sum_{i=1}^{\min(n,m)} (n - \lfloor \frac{n}{i} \rfloor \times i) \times (m - \lfloor \frac{m}{i} \rfloor \times i) =i=1∑min(n,m)(n−⌊in⌋×i)×(m−⌊im⌋×i)
= ∑ i = 1 min ( n , m ) ( n m − n i ⌊ m i ⌋ − m i ⌊ n i ⌋ + i 2 ⌊ n i ⌋ ⌊ m i ⌋ ) = \sum_{i=1}^{\min(n,m)} \Big( nm - ni \lfloor \frac{m}{i} \rfloor - mi \lfloor \frac{n}{i} \rfloor + i^2 \lfloor \frac{n}{i} \rfloor \lfloor \frac{m}{i} \rfloor \Big) =i=1∑min(n,m)(nm−ni⌊im⌋−mi⌊in⌋+i2⌊in⌋⌊im⌋)
= n m ⋅ min ( n , m ) − n × ∑ i = 1 min ( n , m ) i ⌊ m i ⌋ − m × ∑ i = 1 min ( n , m ) i ⌊ n i ⌋ + ∑ i = 1 min ( n , m ) i 2 ⌊ n i ⌋ ⌊ m i ⌋ = nm \cdot \min(n,m) - n \times \sum_{i=1}^{\min(n,m)} i \lfloor \frac{m}{i} \rfloor - m \times \sum_{i=1}^{\min(n,m)} i \lfloor \frac{n}{i} \rfloor + \sum_{i=1}^{\min(n,m)} i^2 \lfloor \frac{n}{i} \rfloor \lfloor \frac{m}{i} \rfloor =nm⋅min(n,m)−n×i=1∑min(n,m)i⌊im⌋−m×i=1∑min(n,m)i⌊in⌋+i=1∑min(n,m)i2⌊in⌋⌊im⌋
令 g n , k = ∑ i = 1 k i ⌊ n i ⌋ g_{n,k} = \sum_{i=1}^k i \lfloor \frac{n}{i} \rfloor gn,k=∑i=1ki⌊in⌋
则:
= n m ⋅ min ( n , m ) − n × g m , min ( n , m ) − m × g n , min ( n , m ) + ∑ i = 1 min ( n , m ) i 2 ⌊ n i ⌋ ⌊ m i ⌋ = nm \cdot \min(n,m) - n \times g_{m,\min(n,m)} - m \times g_{n,\min(n,m)} + \sum_{i=1}^{\min(n,m)} i^2 \lfloor \frac{n}{i} \rfloor \lfloor \frac{m}{i} \rfloor =nm⋅min(n,m)−n×gm,min(n,m)−m×gn,min(n,m)+i=1∑min(n,m)i2⌊in⌋⌊im⌋
显然, g g g 可以整除分块,所以整个式子都可以整除分块。
对于最后的一块,我们令 h n , m , k = ∑ i = 1 k i 2 ⌊ n i ⌋ ⌊ m i ⌋ h_{n,m,k} = \sum_{i=1}^{k} i^2 \lfloor \frac{n}{i} \rfloor \lfloor \frac{m}{i} \rfloor hn,m,k=∑i=1ki2⌊in⌋⌊im⌋,但是注意到:
∑ i = 1 min ( n , m ) i 2 ⌊ n i ⌋ ⌊ m i ⌋ \sum_{i=1}^{\min(n,m)} i^2 \lfloor \frac{n}{i} \rfloor \lfloor \frac{m}{i} \rfloor ∑i=1min(n,m)i2⌊in⌋⌊im⌋ 的计算需要用到公式:
∑ i = 1 n i 2 = n ( n + 1 ) ( 2 n + 1 ) 6 \sum_{i=1}^n i^2 = \frac{n (n+1) (2n+1)}{6} i=1∑ni2=6n(n+1)(2n+1)
但是模意义下的除法不好做。这里有三种解决方法:
当然本人为了方便直接开了 __int128 \text{\_\_int128} __int128,解决了所有的溢出计算问题。反正 ( 1 0 9 ) 3 = 1 0 27 (10^9)^3 = 10^{27} (109)3=1027 肯定不会超过 2 127 2^{127} 2127,因为 2 127 2^{127} 2127 大概有 40 40 40 位。
上述方法已经说明, f f f 和 g g g 均可以在 O ( n + m + min ( n , m ) ) \mathcal{O}(\sqrt{n} + \sqrt{m} + \sqrt{\min(n,m)}) O(n+m+min(n,m)) 的时间内解决。 n n n , m m m 与 min ( n , m ) \min(n,m) min(n,m) 均同级,所以最终时间复杂度为 O ( n ) \mathcal{O}(\sqrt{n}) O(n).
时间复杂度: O ( n ) \mathcal{O}(\sqrt n) O(n).
实际得分: 100 p t s 100pts 100pts.
这个故事告诉我们,清华集训的题并不难,在自己擅长的领域完全可以吊打集训队。(当然离那一天还很遥远)
#pragma GCC optimize(2)
#include
using namespace std;
typedef __int128 ll;
const ll MOD=19940417;
inline ll read(){
char ch=getchar(); int f=1; while(ch<'0' || ch>'9') {
if(ch=='-') f=-f; ch=getchar();}
ll x=0; while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return x*f;}
inline void write(ll x) {
if(x<0) {
putchar('-');write(-x);return;}
if(x<10) {
putchar(char(x%10+'0'));return;}
write(x/10);putchar(char(x%10+'0'));
} //int128 需要快读快输
inline ll sum(ll n) {
return n*(n+1)/2%MOD;} //一维和
inline ll pf(ll n) {
return n*(n+1)*(2*n+1)/6%MOD;} //平方和
inline ll min(ll n,ll m) {
return n<m?n:m;} //手动最小值
inline ll f(ll n) {
ll ans=0;
for(ll l=1,r;l<=n;l=r+1) {
r=n/(n/l);
ans=(ans+(n/l)*(sum(r)-sum(l-1))%MOD)%MOD;
} //printf("%lld\n",ans);
return (n*n-ans)%MOD;
} //整除分块计算 f
inline ll g(ll n,ll k) {
ll ans=0;
for(ll l=1,r;l<=k;l=r+1) {
r=n/(n/l); r=min(r,k); //保证块不超过 k
ans=(ans+(n/l)*(sum(r)-sum(l-1))%MOD)%MOD;
} return ans;
} //整除分块计算 g
inline ll h(ll n,ll m,ll k) {
ll ans=0;
for(ll l=1,r;l<=k;l=r+1) {
r=min(n/(n/l),m/(m/l)); r=min(r,k); //保证块不超过 k
ans=(ans+(n/l)*(m/l)%MOD*(pf(r)-pf(l-1))%MOD)%MOD;
} return ans;
} //整除分块计算 h
int main() {
ll n=read(),m=read(),x=min(n,m);
ll tot1=f(n)*f(m)%MOD; //原本答案
ll tot2=(n*m*min(n,m)-n*g(m,x)-m*g(n,x)+h(n,m,x)+MOD+MOD)%MOD; //多余答案
// write(tot1),putchar(' '),write(tot2),putchar('\n');
write((tot1-tot2+MOD)%MOD); //减法需要处理负数
return 0;
}