题意:求长度为n的数列方案数,数列需满足两个条件:1.均为正整数。2.相邻两个数乘积不能超过m
思路:考虑dp。
设表示前i个点以j结尾的方案数,则有:
可以得出:
双指针+数论分块解决。把每个m/i相同的值抽象成一个点,共同转移即可。
此时设表示在以j结尾(在第j块的最小值)
变形后的dp方程:
从小块开始,另一指针从大块开始往前跳
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod = 1e9 + 7 , N = 110 , M = 1e5 + 10;
int n,m,k,f[2][M],len[M],bel[M],cnt,now;
signed main(){
cin>>n>>m;
int l=1,r=0;
while(l<=m){
r=m/(m/l);
++k;
bel[k]=r;len[k]=(r-l+1);
l=r+1;
}
for(int i=1;i<=k;i++) f[0][i]=len[i]+f[0][i-1];
for(int p=1;p<n;p++){
now^=1;
int j=k;
for(int i=1;i<=k;i++){
while(bel[j]*bel[i]>m) j--;
f[now][i]=(f[now][i-1]+f[now^1][j]*len[i])%mod;
}
}
cout<<f[now][k];
return 0;
}