牛牛与数组(DP)
链接:https://ac.nowcoder.com/acm/problem/21738来源:牛客网
题目描述
牛牛喜欢这样的数组:
1:长度为n
2:每一个数都在1到k之间
3:对于任意连续的两个数A,B,A<=B 与(A % B != 0) 两个条件至少成立一个
请问一共有多少满足条件的数组,对1e9+7取模
1:长度为n
2:每一个数都在1到k之间
3:对于任意连续的两个数A,B,A<=B 与(A % B != 0) 两个条件至少成立一个
请问一共有多少满足条件的数组,对1e9+7取模
输入描述:
输入两个整数n,k
1 ≤ n ≤ 10
1 ≤ k ≤ 100000
输出描述:
输出一个整数
具体思路:
dp[i][j]表示前i个序列,第i个位j的时候的合法情况。
如果是三层暴力的话,肯定会T,我们可以记录第二个for循环的总值,然后再去把不符合的情况给去掉。如果条件1,我们累加这个数前面的数就好了。
对于条件2,我们先预处理出来每个数的倍数,然后再减去不合法的情况就可以了。
AC代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 # define ll long long 4 # define inf 0x3f3f3f3f 5 const int maxn = 2e5+100; 6 const int N = 15; 7 const int mod = 1e9+7; 8 ll dp[N][maxn]; 9 vector<ll>sto[maxn]; 10 int main(){ 11 int n,k; 12 scanf("%d %d",&n,&k); 13 for(int i=1;i<=k;i++){ 14 dp[1][i]=1; 15 } 16 for(int i=1;i<=k;i++){ 17 for(int j=2;j*i<=k;j++){ 18 sto[i].push_back(i*j); 19 } 20 } 21 for(int i=2;i<=n;i++){ 22 ll sum=0; 23 for(int j=1;j<=k;j++){sum=(sum+dp[i-1][j])%mod;} 24 ll tmp=0; 25 for(int j=1;j<=k;j++){ 26 dp[i][j]=(dp[i-1][j]+tmp)%mod; 27 tmp=(tmp+dp[i-1][j])%mod; 28 ll ans=(sum-tmp+mod)%mod;// 把已经算过的情况给删除 29 for(int w=0;w<sto[j].size();w++){ 30 ans=(ans-dp[i-1][sto[j][w]]+mod)%mod; 31 } 32 dp[i][j]=(dp[i][j]+ans)%mod; 33 } 34 } 35 ll ans=0; 36 for(int i=1;i<=k;i++){ 37 ans=(ans+dp[n][i])%mod; 38 } 39 printf("%lld\n",ans); 40 return 0; 41 }