觉得平时写博客的速度太慢了,今晚尝试一下 20 mins 完成一篇有质量的博客qwq
实际上用了 50 分钟qaq
CF1061C Multiplicity
最近做的练习题中最简单的一道了。
结论:元素整除 − > -> −> 分解质因数
题目大意
从序列 a 1 , a 2 , … , a n a_1,a_2,\dots,a_n a1,a2,…,an 中选出非空子序列 b 1 , b 2 , … , b n b_1,b_2,\dots,b_n b1,b2,…,bn,一个子序列合法需要满足 ∀ i ∈ [ 1 , k ] , i ∣ b i ∀\ i\in[1,k],i\ |\ b_i ∀ i∈[1,k],i ∣ bi。求有多少互不相等的合法子序列,答案对 1 0 9 + 7 10^9+7 109+7 取模。
序列 1 , 1 { 1,1 } 1,1 有 2 2 2 种选法得到子序列 1 1 1 ,但 1 1 1 的来源不同,认为这两个子序列不相等。
分析
首先,根据题意不难想到暴力做法:
f i , j = f i − 1 , j + [ a i % j = = 0 ] f i − 1 , j − 1 \large f_{i,j}=f_{i-1,j}+[a_i\%j==0]f_{i-1,j-1} fi,j=fi−1,j+[ai%j==0]fi−1,j−1
其中 f i , j f_{i,j} fi,j 表示前 i i i 个数中选出 j j j 个组成合法子序列的方案数。
时间复杂度是 O ( n 2 ) O(n^2) O(n2),肯定过不了。
分析上述方程,可以将其通过滚动数组将为一维↓↓
f j = f j + [ a i % j = = 0 ] f j − 1 \large f_j=f_j+[a_i\%j==0]f_{j-1} fj=fj+[ai%j==0]fj−1
注意为了不破坏答案正确性,应当将
j
j
j 从大到小更新。我起初 WA 原因
这时我们发现,当 a i % j ! = 0 a_i\%j\ !=0 ai%j !=0 时, f j f_j fj 保持不变。换句话说,只有当 a i % j = = 0 a_i\%j==0 ai%j==0 时, f i f_i fi 才会更新。
所以对于每个
a
i
a_i
ai,我们可以先处理出
a
i
a_i
ai 的质因子,并将其质因子排序,再进行状态转移,本题就可以过了。 实际上 20 mins 就写了以上这么点((
时间复杂度分析:
设
a
i
a_i
ai 的因子数位
f
a
c
i
fac_i
faci,那么时间复杂度为
O
(
n
⋅
max
i
∈
[
1
,
n
]
f
a
c
i
log
f
a
c
i
)
\large O(n\cdot \max\limits_{i\in[1,n]} fac_i\log fac_i)
O(n⋅i∈[1,n]maxfacilogfaci),注意
log
\log
log 的存在在于需要将质因子排序。
实际上,当
a
i
≤
1
0
6
a_i\le 10^6
ai≤106 时,
f
a
c
i
fac_i
faci 的最大值为 240,最大时间复杂度为
O
(
1
0
5
⋅
240
⋅
8
)
=
O
(
1.92
×
1
0
8
)
O(10^5\cdot 240\ \cdot 8)=O(1.92\times10^8)
O(105⋅240 ⋅8)=O(1.92×108),3 s 时限可以过。
注意因为
a
i
a_i
ai 质因子的最大值接近
1
0
6
10^6
106,
f
\large f
f 数组要开
1
0
6
10^6
106 。我后来 RE 的原因
当然,将 a i a_i ai 质因子筛选,保证全部小于 n n n 再转移 f \large f f 也行。
C o d e Code Code
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5,M=1e9+7;
int n,ans,b[N],f[N*10];
int main(){
scanf("%d",&n);
f[0]=1;
for(int i=1;i<=n;i++){
int a,c=0;
scanf("%d",&a);
for(int j=1;j*j<=a;j++){
if(a%j==0){
b[++c]=j;
if(j*j!=a) b[++c]=a/j;
}
}
sort(b+1,b+c+1);
for(int j=c;j>=1;j--) (f[b[j]]+=f[b[j]-1])%=M;
/*for(int j=c;j>=1;j--){ //Method 2 : ensure that all are less than N.
if(b[j]>n) continue;
(f[b[j]]+=f[b[j]-1])%=M;
}*/
}
for(int i=1;i<=n;i++) (ans+=f[i])%=M;
printf("%d",ans);
return 0;
}