问题描述
试题编号: | 202104-4 |
试题名称: | 校门外的树 |
时间限制: | 1.0s |
内存限制: | 512.0MB |
问题描述: | 问题描述X 校最近打算美化一下校园环境。前段时间因为修地铁,X 校大门外种的行道树全部都被移走了。现在 X 校打算重新再种一些树,为校园增添一抹绿意。 X 校大门外的道路是东西走向的,我们可以将其看成一条数轴。在这条数轴上有 n 个障碍物,例如电线杆之类的。虽然障碍物会影响树的生长,但是障碍物不一定能被随便移走,所以 X 校规定在障碍物的位置上不能种树。n 个障碍物的坐标都是整数;如果规定向东为正方向,则 n 个障碍物的坐标按照从西到东的顺序分别为 a1,a2,⋯,an。X 校打算在 [a1,an] 之间种一些树,使得这些树看起来比较美观。 X 校希望,在一定范围内,树应该是等间隔的。更具体地说,如果把 [a1,an) 划分成一些区间 [ap1,ap2),⋯,[apm−1,apm)(1=p1<p2<⋯<pm=n),那么每个区间 [api,api+1) 内需要至少种一棵树,且该区间内种的树的坐标连同区间端点 api,api+1 应该构成一个等差数列。不同区间的公差,也就是树的间隔可以不相同。 例如,如果障碍物位于 0,2,6 这三处,那么我们可以选择在 [0,2) 和 [2,6) 分别种树,也可以选择在 [0,6) 等间隔种树。如果是分别在 [0,2) 和 [2,6) 种树,由于每个区间内至少要种一棵树,坐标 1 上必须种树;而 [2,6) 上的树可以按照 1 的间隔种下,也可以按照 2 的间隔种下。下图表示了这两种美观的种树方案,其中橙色的圆表示障碍物,绿色的圆表示需要在这个位置种树,箭头上的数字表示种下这棵树时对应的间隔为多少。 对区间 [0,2) 和 [2,6) 分别以 1 和 2 的间隔种树是美观的
而如果选择在 [0,6) 区间等间隔种树,我们只能以 3 的间隔种树,因为无论是选择间隔 1 或者间隔 2,都需要在坐标 2 上种树,而这个位置已经有障碍物了。下图分别表示了间隔为 3,2,1 时的种树情况,红色箭头表示不能在这里种树。
一般地,给定一个区间 [al,ar),对于树的坐标的集合 T⊂(al,ar)(T⊂Z),归纳定义 T 在 [al,ar) 上是美观的:
根据这一定义,空集在任意区间上都不是美观的;另外,如果存在下标 i 使得 ai∈T,那么 T 一定不是美观的。 我们称两种种树的方案是本质不同的,当且仅当两种方案中,种树的坐标集合不同。请帮助 X 校对 [a1,an) 求出所有本质不同的美观的种树方案。当然,由于方案可能很多,你只需要输出总方案数对 109+7 取模的结果。 输入格式输入的第一行包含一个正整数 n,表示障碍物的数量。 输入的第二行包括 n 个非负整数 a1,⋯,an,表示每个障碍物的坐标。 保证对 i=1,2,⋯,n−1,ai<ai+1。 输出格式输出一个非负整数,表示本质不同的美观的种树方案的数量对 109+7 取模的结果。 样例输入 Data 样例输出 Data 样例说明这组样例即为题面描述中提到的那组。 样例输入 Data 样例输出 Data 样例输入 Data 样例输出 Data 评测用例规模与约定对于 10% 的数据,保证 n=2; 对于 30% 的数据,保证 n≤10; 对于 60% 的数据,保证 n≤100,ai≤1000; 对于 100% 的数据,保证 2≤n≤1000,0≤ai≤100,000,且至少存在一种美观的种树方案。 |
#include<iostream>
#include<vector>
#include<set>
using namespace std;
vector<int>f[100001];
set<int>divisor;
int a[100001];
const int mod = 1000000007;
long long methods(int x, int y) {
long long method = 0;
int sub = a[y] - a[x];
divisor.insert(sub);
for (int i = 0; i < f[sub].size(); ++i) {
if (divisor.find(f[sub][i]) != divisor.end())
continue;
else {
divisor.insert(f[sub][i]);
method++;
}
}
return method;
}
int main()
{
int n;
cin >> n;
for (int i = 1; i <= n; ++i)
cin >> a[i];
for (int i = 1; i <= a[n] / 2; ++i)
for (int t = 2*i; t <= a[n]; t += i)
f[t].push_back(i);
long long dp[1001] = { 1,1 };
for (int i = 2; i <= n; ++i) {
divisor.clear();
for (int t = i - 1; t >= 1; --t)
dp[i] = (dp[i]+ (dp[t] * (methods(t, i) % mod))%mod) % mod;
}
cout << dp[n];
return 0;
}