校门外的树
原题链接
思考过程:
1.对于一整个区间,划分的可能性->区间的划分一定要求区间的起点和终点都是障碍物
2.对于一个特定的区间,种树的可能性
3.不同的区间划分,可能出现相同的种树方案
套分代码:
对于单个的区间B[0]到B[1],仅需枚举其所有的约数即可
#include<iostream>
using namespace std;
#define NMAX 1010
#define MOD 1000000007
int n;
int B[NMAX];
int res = 0;
int main() {
cin >> n;
if (n == 2) {
cin >> B[0] >> B[1];
int dis = B[1] - B[0];
for (int i = 1; i <= dis / 2; i++) {
if (!(dis % i)) res = (res + 1) % MOD;
}
cout << res << endl;
}
}
解题思路参考
使用动态规划的思想,dp[i]代表的是a0到ai的可能的种树方案。
假设cac(a,b)代表的是区间[a,b)的种树方案数。
对于dp[i+1],枚举aj(0<j<i),将a0到ai+1的种树方案分成两个部分,a0到aj和aj到ai+1。
那么就有递推公式dp[i+1]=sum(dp[j]*cac(aj,ai+1))。
对于不同的j,下面证明不可能存在相同的方案。假设j1和j2的种树方案相同,那么j1和j2在aj到ai+1上的种树方案相同,假设j1<j2,那么必有j2在j1的种树方案上,这与不能在障碍物上种树相违背。
需要注意的是,对于cac(aj,ai+1)的计算,需要剔除掉使得某棵树种到障碍物上的情况。其实现方案为,对于j,从i-1进行遍历,然后逐步向前取值,对于其可能的差值k,若其在前面的计算中没有出现过(代表不可能种到障碍物上),则代表可使用,并将其置为已使用。因此,总的来说,在整个递推的过程中,实现了障碍物的避免。
#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
#define NMAX 1010
#define MMAX 100010
#define MOD 1000000007
typedef long long LL;
int dp[NMAX];
int A[NMAX];
int n;
bool ik[MMAX];
vector<int > appnum[MMAX];
int main() {
for (int i = 1; i < MMAX; i++) {
for (int k = 2; i * k < MMAX; k++) {
appnum[i * k].push_back(i);
}
}
cin >> n;
for (int i = 1; i <= n; i++) cin >> A[i];
dp[1] = 1;
for (int i = 2; i <= n; i++) {
memset(ik, 0, sizeof(ik));
for (int j = i - 1; j > 0; j--) {
int d = A[i] - A[j];
int res = 0;
for (int k = 0; k < appnum[d].size(); k++) {
if (!ik[appnum[d][k]]) {
res++;
ik[appnum[d][k]] = true;
}
}
ik[d] = true;
//dp[i] = (dp[i]+(LL)(dp[j] * res)) % MOD;
dp[i] = (dp[i] + (LL)dp[j] * res) % MOD;
}
}
cout << dp[n] << endl;
}
debug:
1.关于强制类型转化
LL先作用到x上,这样后续的类型就都是LL了,而LL作用到x*y上,相当于已经溢出了
.