题面
给定 T
组 n,m
,求:
i=0∑m(in)
结果对 109+7
取模。
数据范围:
1≤T≤105
1≤m≤n≤105
题目链接
分块
分析
虽然经过 O(n)
的预处理后我们可以以 O(1)
算出 (in)
,但是 O(Tn)
的复杂度显然是不能被接受的。
那怎么办…… 我们希望复杂度能够降至 O(Tn)
左右…… 分块?
分块的思想即大段维护,局部朴素。假设块长为 L
,令数组 A[i][j]
代表 k=0∑L⋅j(ki)
,即前 j
块的前缀和。
这样一来,对于给定的 n,m
,令 S=⌊LA⌋
,我们可以把待求的值分为两部分:
i=0∑m(in)=A[n][S]+i=L⋅S+1∑m(in)
取 L=n
左右的话,每一次计算的复杂度就变成了 O(n)
级别。接下来我们需要在 O(n)
级别的复杂度内完成对 A
的预处理。
我们考虑 A[i][j]
和 A[i−1][j]
间能否在 O(1)
内完成转移。
首先,我们知道:
(mn)=(mn−1)+(m−1n−1)
那么相应地:
i=1∑m(in)=(0n)+(1n)+⋯+(mn)=2⋅(0n−1)+2⋅(1n−1)+⋯+2⋅(m−1n−1)+(mn−1)=2⋅i=0∑m(in−1)−(mn−1)
所以也就有:
A[i][j]=2⋅A[i−1][j]−((j+1)⋅L−1i−1)
其中 (j+1)⋅L−1
也就是第 j
块的最后一个元素。而这个组合数我们可以用预处理阶乘和逆元的方式在 O(1)
内求得。
另外需要注意的是,在 L∣i
时(也就是末尾出现了一个新的块时),需要手动处理一下: A[i][⌊Li⌋]=A[i][⌊Li⌋−1]+1
。否则如果新出现的这一块一直是 0
的话后续转移会出问题。
另外,如果本题按照 N
取块长三百左右的话貌似会 MLE…… 我是取四百左右过的。
实现
完整参考代码
莫队
分析
当得知这道题还可以莫队时…… orz。
首先我们不妨记 S(n,m)=i=0∑m(in)
。
由上我们已经得到了:
S(n,m)=2⋅S(n−1,m)−(mn−1)
那么反过来:
S(n,m)=21⋅(S(n+1,m)+(mn))
好了,n
的转移方式我们已经得到了。那么 m
的转移呢?这不是很显然吗……
S(n,m)=S(n,m−1)+(mn)
S(n,m)=S(n,m+1)−(mn)
现在 n
和 m
的 O(1)
转移方式都有了…… 我们好像真的可以用莫队了诶。真心佩服出题人的脑洞。
实现
完整参考代码