小红的元素分裂(dp分解因子)
链接:https://ac.nowcoder.com/acm/contest/69117/C
来源:牛客网
小红拿到了一个数组,她每次可以进行如下操作之一:
·选择一个元素\(x\),将其分裂为\(1\)和\(x-1\)。
·选择一个元素\(x\),将其分裂为\(a\)和\(b\),需要保证\(a * b = x\)
小红希望用最少的操作次数,将所有数组的所有元素全部变成\(1\)。你能帮帮她吗?
输入描述:
第一行输入一个正整数\(n\),代表数组的长度。
第二行输入\(n\)个正整数\(a_i\),代表小红拿到的数组。
\(1\leq n,a_i \leq 10^5\)
输出描述:
一个整数,代表最小的操作次数。
示例1
输入
2
2 6
输出
5
说明
第一次,对第一个元素进行第一个操作,数组变成[1,1,6]。
第二次,对第三个元素进行第二个操作,数组变成[1,1,2,3]。
第三次,对第三个元素进行第一个操作,数组变成[1,1,1,1,3]。
第四次,对第五个元素进行第一个操作,数组变成[1,1,1,1,2,1]。
第五次,对第五个元素进行第一个操作,数组变成[1,1,1,1,1,1,1]。
目标是全部变成1,所以我们是1的时候直接初始值为0即可,然后我们发现每一个数可以分裂为两个乘积为x的约数,然后我们直接枚举所有约数即可然后看哪一种情况最优即可
时间复杂度:\(n * sqrt(n)\)
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=3e5+100;
int f[maxn];
int main(){
f[2]=1;
for(int i=3;i<=1e5;i++){
f[i]=f[i-1]+1;
for(int j=2;j*j<=i;j++){
if(i%j==0){
f[i]=min(f[i],f[j]+f[i/j]+1);
}
}
}
int t;
cin>>t;
long long int ans=0;
while(t--){
int x;
cin>>x;
ans+=f[x];
}
cout<<ans<<endl;
}