算法刷题记录(Day 66)

校门外的树

原题链接
思考过程:
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上,相当于已经溢出了
在这里插入图片描述
.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值