C. Multiplicity(思维+dp优化)

https://codeforces.com/problemset/problem/1061/C


思路:

dp[i][j]:前i个且第i个的长度为j的序列个数

dp[i][j]+=dp[i-1][j]; 前i个,且当前i为终点长度为j的序列
if(a[i]%j==0) dp[i][j]+=dp[i-1][j-1];

O(n^2)的优化,由于a[i]不是所有的长度j都满足,满足的是其所有约数。也就是O(sqrt)

于是转移从其预处理的约数位置转移过来。

比如其中一个因数是7,那么加上长度为6的总数。

因为压缩维度,类似01背包的倒序。

从大到小枚举因子。

#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=3e6+100;
typedef long long LL;
LL mod=1e9+7;
inline LL read(){LL x=0,f=1;char ch=getchar();	while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;}
LL dp[maxn];
vector<LL>v[maxn];
void solve(LL id,LL num){///求num的所有因子(非质因子)
    for(LL i=1;i<=sqrt(num);i++){
        if(num%i==0){
            if(i*i==num){
                v[id].push_back(i);break;
            }
            else{
                v[id].push_back(i);
                v[id].push_back(num/i);
            }
        }
    }
    sort(v[id].begin(),v[id].end());
}
int main(void)
{
  cin.tie(0);std::ios::sync_with_stdio(false);
  LL n;cin>>n;
  for(LL i=1;i<=n;i++){
     LL x;cin>>x;
     solve(i,x);
  }
  ///dp[i][j]+=dp[i-1][j]; 前i个,且当前i为终点长度为j的序列
  ///if(a[i]%j==0) dp[i][j]+=dp[i-1][j-1];
  dp[0]=1;

  for(LL i=1;i<=n;i++){
     for(LL j=v[i].size()-1;j>=0;j--){
         dp[v[i][j]]=(dp[v[i][j]]%mod+dp[v[i][j]-1]%mod)%mod;

     }
  }
  LL ans=0;
  for(LL j=1;j<=n;j++){
    ans=(ans%mod+dp[j]%mod)%mod;
  }
  cout<<ans<<"\n";
return 0;
}

猜你喜欢

转载自blog.csdn.net/zstuyyyyccccbbbb/article/details/114680488