好题笔记
CF1061C Multiplicity
这是一道用滚动数组来去优化时间和空间的dp题目,题面就不加以解释了,直接上正解。
对于这种取数的dp其实状态都是套路,第x个成为子集里第k个数与否,可以就dp[x][k]=dp[x-1][k-1]+1,如果不可以就dp[x][k]=dp[x-1][k-1],这个转移方程好去想出来,但是不论是二维数组的空间还是两层循环的时间都不可以,所以我们呢发现dp的状态只和上一个状态有关,所以可以用滚动数组来去优化空间,并且我可以在每一个数被枚举到的时候找出他的所有因数,因为假如dp[x][k]的k不是a[x]d的因数那么我们接下来的状态转移完全是没有必要的,于是我们这个转移方程就呼之欲出了,dp[k]=dp[k]+dp[k-1] (其中k是指x的因数)
注意这个题虽然我现在已经口头ac了,但是其实还是有好多细节 1.滚动数组一般都是从后往前枚举,是为了防止同一层的状态相互更新。2. 再加入因数,我们不要用sqrt,这个太慢了,直接用ii。 3. 找到因数,还要判断ii==x,如果是完全平方数的话就会压进去两次 4. 我们找到了factor,但是要注意factor<=x,x是我现在找了几个数是,才会被操作,要不然会数组越界re掉。
最后代码如下
#include<bits/stdc++.h>
using namespace std;
#define MOD 1000000007
int n,a[100005];
void get_input(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
}
vector<int> fac;
getying(int x){
for(int i=1;i*i<=x;i++){
if(x%i==0){
fac.push_back(i);
if(i*i!=x)
fac.push_back(x/i);
}
}
sort(fac.begin(),fac.end(),greater<int>() );
}
int dp[100005];
void getans(){
dp[0]=1;
for(int x=1;x<=n;x++){
getying(a[x]);
for(int i=0;i<fac.size();i++){
if(fac[i]<=x)
dp[fac[i]]=(dp[fac[i]]+dp[fac[i]-1])%MOD;
}
fac.clear();
}
int xum=0;
for(int i=1;i<=n;i++){
xum=(xum+dp[i])%MOD;
}
printf("%d",xum%MOD);
}
int main(){
get_input();
getans();
return 0;
}