F - Small Products
怎么说呢?目前超了自己水平两个档次的题。
第一个档次熟练掌握
d
p
dp
dp
第二个档次熟练掌握分块
这道题:参考大佬
要求求相邻元素乘积 ≤ N ≤N ≤N的序列数。 N ≤ 1 e 9 N≤1e9 N≤1e9
序列数考虑
d
p
dp
dp
显然:
d
p
[
i
]
[
j
]
=
∑
x
∗
j
≤
N
d
p
[
i
−
1
]
[
x
]
dp[i][j]=\sum_{x*j≤N}dp[i-1][x]
dp[i][j]=∑x∗j≤Ndp[i−1][x]
但是显然第二维大小不符合要求。
这种
1
e
9
1e9
1e9一般都是分块或者数学(数学一般是
1
e
18
1e18
1e18)
这道题是分块的做法:值得学习。
我们考虑前
N
\sqrt{N}
N个可以直接利用,后面的部分可以划分成
N
\sqrt{N}
N块。
第
i
i
i块代表了使得
i
∗
k
≤
N
i*k≤N
i∗k≤N成立且
i
i
i唯一的所有
k
k
k。
意思就是说这里的
k
k
k只能和
i
i
i组合,与
i
+
1
i+1
i+1不能组合(在后面的式子可以发现被去除了),与
i
−
1
i-1
i−1组合的部分在前面已经有了。
第
i
i
i块的数量为
N
i
−
N
i
+
1
\frac{N}{i}-\frac{N}{i+1}
iN−i+1N
数学证明并不会,但举例子比较容易懂。
比如说第一块,只能被
1
1
1唯一整除的。
N
/
1
=
N
N/1=N
N/1=N是不考虑唯一的情况
N
/
2
N/2
N/2是不考虑唯一,被
2
2
2整除的。
唯一被
1
1
1整除的显然是
N
−
N
/
2
N-N/2
N−N/2。以此类推。
接下来是正戏。
我们考虑分类讨论:
第一部分是第
i
i
i位放的是
N
\sqrt{N}
N以内的。
S
[
i
]
[
j
]
S[i][j]
S[i][j]
第二部分是第
i
i
i位放的是以外的,这个时候要利用分块处理。
B
[
i
]
[
j
]
B[i][j]
B[i][j]
答案显然是
∑
i
=
1
N
S
[
k
]
[
i
]
+
B
[
k
]
[
i
]
\sum_{i=1}^{\sqrt{N}} S[k][i]+B[k][i]
∑i=1NS[k][i]+B[k][i]
S
[
i
]
[
j
]
S[i][j]
S[i][j]怎么用
d
p
dp
dp解决呢,考虑第
j
j
j位放的是小的数,那么第
j
−
1
j-1
j−1位可以放小的数和大的数。
小的数无所谓,对于大的数只能从
[
j
,
N
]
[j,\sqrt{N}]
[j,N]的块用,小于的会导致数过大,超过
N
N
N.
所以
S
[
i
]
[
j
]
=
∑
k
=
1
N
S
[
i
−
1
]
[
k
]
+
∑
k
=
j
N
B
[
i
−
1
]
[
k
]
S[i][j]=\sum_{k=1}^{\sqrt{N}} S[i-1][k]+\sum_{k=j}^{\sqrt{N}} B[i-1][k]
S[i][j]=∑k=1NS[i−1][k]+∑k=jNB[i−1][k]
对于
B
[
i
]
[
j
]
B[i][j]
B[i][j],前一位只能放小数,不过这里的
j
j
j表示的是块,所以还需要乘上块数里的数量。
所以
B
[
i
]
[
j
]
=
(
N
i
−
N
i
+
1
)
∗
∑
k
=
1
j
S
[
i
−
1
]
[
k
]
B[i][j]=(\frac{N}{i}-\frac{N}{i+1})*\sum_{k=1}^{j} S[i-1][k]
B[i][j]=(iN−i+1N)∗∑k=1jS[i−1][k]超过
j
j
j的显然会超。
这样子做
d
p
dp
dp复杂度是
k
∗
N
∗
N
k*\sqrt{N}*\sqrt{N}
k∗N∗N
考虑加的操作,可以简化为前缀和,利用前缀和可以实现
k
∗
N
k*\sqrt{N}
k∗N
有个小细节就是第
N
\sqrt{N}
N块和放
N
\sqrt{N}
N等价。取其一即可。
#include<bits/stdc++.h>
#define FOR(i,l,r) for(int i=l;i<=r;i++)
#define ll long long
using namespace std;
const ll mod = 1e9+7;
ll n;int k;
ll S[110][202000],B[110][202000];
int main(){
cin>>n>>k;
ll d=sqrt(n);
ll ans=0;
S[0][1]=1;
FOR(i,1,k){
FOR(j,1,d)S[i-1][j]=(S[i-1][j]+S[i-1][j-1])%mod;
FOR(j,1,d)B[i-1][j]=(B[i-1][j]+B[i-1][j-1])%mod;
FOR(j,1,d){
S[i][j]=(S[i-1][d]+B[i-1][d]-B[i-1][j-1]+mod)%mod;
B[i][j]=(n/j-n/(j+1))*S[i-1][j]%mod;
if(j==n/j)B[i][j]=0;//SжагаСЫ
}
}
FOR(i,1,d)ans=(ans+S[k][i]+B[k][i])%mod;
cout<<ans<<endl;
}