C. Multiplicity
题目链接:https://codeforc.es/contest/1061/problem/C
题意:
给出一串数,问它的“好序列“有多少。好序列的定义是,首先是一个子序列(顺序可以打乱),其次,序列相应位置的数可以除尽该位置编号。
题解:
这题是dp,我没有想到,主要是状态的定义。
定义dp(i,j):在a1,a2...ai中长度为j的好序列的个数,这样dp转移方程就为:if ai%j==0: dp(i,j)=dp(i-1,j-1)+dp(i-1,j) , else: dp(i,j)=dp(i-1,j) 。
由于二维数组空间太大,又因为状态都是从i-1转移过来,所以可以对空间复杂度进行优化。
代码中,用一个vector来储存ai能放在的位置,这样与对空间复杂度进行优化相配,能更好地逆推。
代码如下:
#include <bits/stdc++.h> using namespace std; typedef long long ll ; const int N = 1000005,MOD = 1e9+7; ll dp[N]; int n; int a[N]; int main(){ scanf("%d",&n); dp[0]=1; for(int i=1;i<=n;i++){ scanf("%d",&a[i]); vector <int> pos; for(int j=1;j*j<=a[i];j++){ if(a[i]%j==0){ pos.push_back(j); if(a[i]/j!=j) pos.push_back(a[i]/j); } } sort(pos.begin(),pos.end()); reverse(pos.begin(),pos.end()); for(int i=0;i<pos.size();i++){ dp[pos[i]]+=dp[pos[i]-1]; dp[pos[i]]%=MOD; } } ll ans = 0; for(int i=1;i<=n;i++) ans+=dp[i] , ans%=MOD; printf("%I64d",ans); return 0; }