题意:给出一个数列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]