- 由于以障碍物作为划分区间可以考虑最后一组划分区间的公差,乘以该区间左端点的划分数目。
- 设当前障碍物编号为i(从0开始),以该障碍物为止的方案数目为dp[i]。则 d p [ i ] = ∑ j < i d p [ i ] ⋅ c n t [ j , i ] dp[i] = \sum_{j < i}dp[i] \cdot cnt[j,i] dp[i]=∑j<idp[i]⋅cnt[j,i],其中 c n t [ j , i ] cnt[j,i] cnt[j,i]为从第j个障碍物到第i个障碍物的种树个数,且不碰到中间障碍物(否则产生重复)
- 因子预处理(做过,见某次leetcode周赛T4):nlogn复杂度
- 解决方案:维护vis数组,将遇到的因子(即公差)去除。
#include <iostream>
#include<vector>
#include<stdio.h>
#include<string.h>
using namespace std;
bool vis[100005];
int main()
{
int mod = 1e9 + 7;
int n;
cin >> n;
int a[n];
for(int i = 0;i<n;i++)
cin >> a[i];
vector<int> b[a[n-1] + 1]; //每个数具有的因子
for(int i = 1;i<=a[n-1];i++)
{
for(int j = i;j<=a[n-1];j+=i)
b[j].push_back(i);
}
int dp[n];
memset(dp,0,sizeof(dp));
dp[0] = 1;
for(int i = 1;i<n;i++)
{
memset(vis,0,sizeof(vis));
for(int j = i - 1;j>=0;j--)
{
int ans = 0;
for(int e : b[a[i] - a[j]])
{
if(e != a[i] - a[j] && !vis[e]) //至少种一棵树,因子还没有遇到过
{
ans++;
vis[e] = true;
}
}
vis[a[i] - a[j]] = true;
dp[i]=(dp[i]+(((long long)dp[j] * ans) % mod))%mod; //更新方案总数
}
}
printf("%d",dp[n-1]);
}