CodeForces - 1061C Multiplicity

Posted on 2021-12-26 15:10  Capterlliar  阅读(35)  评论(0编辑  收藏  举报

题意:给出一个数列a,挑选其中一个子序列b,如果子序列中每个b[i]能被i整除,那它是一个好数列。求好数列的个数模1e9+7。

解:既然是挑选子序列,那么原序列顺序不变。设dp[i]为到第i个数好数列的个数。现在新来了一个数,它可以排在每个因数的位置,比如因数有2那它可以排在第二个,现在我们想知道到前i-1位置长度为1的有几个,那再加一维。

dp[i][j]表示到第i个数,长度为j的好数列个数,现在可以转移了。时间复杂度n√n,三秒,可以跑。

if(a[i]%k==0)
  dp[i][k]+=dp[i-1][k-1];

一看数组要开1e6*1e6,这不行,滚动一下。于是所有因子要从大往小滚,那不如提前把所有因子筛好。上网紧急学习(抄袭)因子筛,三行,很快乐。网上说是nlogn复杂度,但我目测是nln(n)?差不多,随便吧。

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define maxx 1000005
#define eps 0.00000001
#define inf 0x3f
#define mod 1000000007
//#define int long long
int n;
ll a[maxx],dp[maxx]={0};
vector<int> fac[maxx];
signed main() {
    for(int i=1;i<=1000000;i++){
        for(int j=1;j<=1000000/i;j++)
            fac[i*j].push_back(i);
    }
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%lld",&a[i]);
    dp[0]=1;
    for(int i=1;i<=n;i++){
        for(int j=fac[a[i]].size()-1;j>=0;j--){
            int t=fac[a[i]][j];
            dp[t]=(dp[t]+dp[t-1])%mod;
        }
    }
    ll ans=0;
    for(int i=1;i<=1000000;i++) {
        ans = (ans + dp[i]) % mod;
    }
    printf("%lld\n",ans);
    return 0;
}
//if(a[i]%k==0)
//dp[i][k]+=dp[i-1][k-1]
View Code