–>题目传送门<–
题目描述
牛牛喜欢这样的数组:
1:长度为n
2:每一个数都在1到k之间
3:对于任意连续的两个数A,B,A<=B 与(A % B != 0) 两个条件至少成立一个
请问一共有多少满足条件的数组,对1e9+7取模
输入描述:
输入两个整数n,k
1 ≤ n ≤ 10
1 ≤ k ≤ 100000
输出描述:
输出一个整数
题意:
找出所有长度为n且满足任意连续的两个数A,B(数列中A的位置在B前面)A<=B或者A不是B的倍数。
题解:
今天看见牛客网讨论区有人问这道题目,恰好我曾经写过。故写下拙作一篇,望能对有需要的人提供一点点帮助!
此题可用动态规划求解,设立一个数组dp[i][j](dp[i][j]表示长度为i且尾数为j的数组个数(对1e9+7取模))
那么对于每一个dp[i][j]来说,数列的来源都是dp[i-1][x](x为1至j)来的。即为在符合题目条件下对长度为i-1的数列后端加上数字j作为其新的尾数。
直接找满足的数列个数很容易疏漏,但是很容易找到不满足题目条件的情况。所以我们可以利用数列总数减去不满足条件的个数即可得到答案。
满足A%B!=0,即表示A不是B的倍数即可,这个条件也包含了A<B,对于A==B,剔除时特判即可。
(也就是在剔除时,直接从2倍的B开始即可)
附上AC代码:
#include <iostream>
#include <vector>
using namespace std;
#define LL long long
const int mod =1e9+7;
int main()
{
ios::sync_with_stdio(false);
int n,k;
LL ans=0;
int dp[11][100001];//dp[i][j]表示长度为i且尾数为j的数组个数(对1e9+7取模)
cin>>n>>k;
for(int i=0;i<=k;i++)dp[1][i]=1;
int sum,sum1;
for(int i=2;i<=n;i++)
{
sum = 0;
//长度为i-1的数列数目
for(int j = 1; j <= k; j++)
{
sum += dp[i-1][j];
sum %= mod;
}
for(int j = 1; j <= k; j++)
{
sum1 = 0;
for(int x = j+j; x <= k; x+=j)
{
sum1 += dp[i-1][x];
sum1 %= mod;
}
//长度为i尾数为j的数列数目 = 长度为i-1的所有 减去 长度为i-1尾数是j的倍数的
dp[i][j] = (sum - sum1) % mod;//过程:相当于在长度为i-1的数列的后面加上一个数j的数组个数
}
}
for(int i=1;i<=k;i++)
{
ans+=dp[n][i];
ans%=mod;
}
cout<<ans<<endl;
return 0;
}
若有什么地方有问题或者有看不懂的,欢迎指正和评论!