题:https://codeforces.com/contest/1061/problem/C
题意:给你一个序列,我们求他们子序列的个数,这个子序列有个限制就是每一个子序列上的值都必须是能整除他的下标,问有多少个
分析:考虑dp,我们先考虑二维的dp,定义dp[i][j]表示前i个数中,能从中提取出j个”好“序列,所以dp[i][j]就可以从dp[i-1][j-1]+dp[i-1][j]得来(前提是a[i]%j==0).显然a[i]%j!=0时dp[i][j]=dp[i-1][j]
但这样写会MLE,所以我们将这个二维数组压缩。我们发现,我们只是在a[i]%j==0的条件下才有更新值,也就相当于前缀和,所以我们只对因子进行更新,dp[j]=dp[j]+dp[j-1]
#include<bits/stdc++.h> using namespace std; #define pb push_back typedef long long ll; const int M=1e5+5; const int mod=1e9+7; vector<int>a[M]; ll b[M],dp[M]; stack<int>sta; void solve(int x){ int temp=b[x]; for(int i=1;i*i<=temp;i++){ if(temp%i!=0) continue; if(i*i==temp) a[x].pb(i); else a[x].pb(i),sta.push(temp/i); } while(!sta.empty()){ a[x].pb(sta.top()); sta.pop(); } } int main(){ int n; cin>>n; for(int i=0;i<n;i++){ scanf("%lld",&b[i]); solve(i); } dp[0]=1; for(int i=0;i<n;i++){ for(int j=a[i].size()-1;j>=0;j--){ int temp=a[i][j]; if(temp<=n&&dp[temp-1]){ dp[temp]=(dp[temp]+dp[temp-1])%mod; } } } ll ans=0; for(int i=1;i<=n;i++) ans+=dp[i],ans%=mod; cout<<ans<<endl; }