牛牛与数组(dp的优化)

题目描述

牛牛喜欢这样的数组:
1:长度为n
2:每一个数都在1到k之间
3:对于任意连续的两个数A,B,A<=B 与(A % B != 0) 两个条件至少成立一个

请问一共有多少满足条件的数组,对1e9+7取模

输入描述:

输入两个整数n,k
1 ≤ n ≤ 10
1 ≤ k ≤ 100000

输出描述:

输出一个整数

---------------------------------------------------------------------------------------------------------------------------

这个题目可以用dp解决,dp[i][j]表示当前选择了i个数字并且当前的数字为j时的方案数,dp[i][j]的来源是dp[i-1][x]即dp[i-1]的所有值,需要循环遍历求和相加,注意,需要判断一下是否满足任意连续的两个数字A,B,A<=B 与(A % B != 0)是否成立,原因是dp[i][j]的值需要由前面的数字来确定,如果不满足条件的话就不能够加上。重点是这样写的话需要三个循环,会TLE,需要对dp进行优化。
分析问题发现,题目的约束条件真实含义是,A不能是B的多余1的倍数,分析原循环发现每个dp[i][j]加的是上一层的和,所以可以先求和,再对每一个进行相加,但是因为不能加上多余1的整数倍那些值,所以可以先加上,然后将所有的那些值再减去即可。
(ps:我的代码中写的状态转移方程并非是与题解中的一致,代码中的转移方程来自于自己写的DFS,该转移方程也是对的,但是要注意转移方程不同,初始化对象不同)

#include<bits/stdc++.h>
using namespace std;
int n, k;
int dp[12][100010];
int pre[12][100010];
const int mod = 1e9 + 7;
void in() {
	scanf("%d %d", &n, &k);
}
void work() {
	for (int i = 1; i <= k; i++) {
		dp[n - 1][i] = 1;
	}
	for (int i = n - 2; i >= 0; i--) {//遍历当前是第几个数字 
//		for (int j = 1; j <= k; j++) {//遍历当前的数字是哪一个 
//			for (int q = 1; q <= k; q++) {//遍历当前数字的前一个数字是多少 
//				if (q <= j || q % j) {
//					dp[i][q] += dp[i + 1][j];
//					dp[i][q] %= mod;
//				}
//			}
//		}
		int ans = 0;
		for (int j = 1; j <= k; j++) {
			ans = (ans + dp[i + 1][j]) % mod;
		}
		for (int j = 1; j <= k; j++) {
			int sum = 0;
			for (int q = j + j; q <= k; q += j) {
				sum += dp[i + 1][q];
				sum %= mod;
			}
			dp[i][j] = (ans - sum) % mod;
		}
	}
	int res = 0;
	for (int i = 1; i <= k; i++)res = (res + dp[0][i]) % mod;
	printf("%d", res%mod);
}
int main()
{
	in();
	work();
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值