分析
我们不难将条件转换为前缀和的形式,即
pre[i]>=pre[i-1]*2,pre[i]>0,pre[k]=n。
所以我们用dp[i][j]表示考虑到第i个数且pre[i]=j的情况下的方案数。我们发现一一转移的复杂度并不行,于是我们考虑只让dp[i-1][j]转移到dp[i][j*2],然后在利用前缀和的思想将dp[i][j]转移到dp[i][j+1],这样可以将复杂度优化到O(nk),然后使用滚动数组就可以了。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<ctime>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
const int mod = 998244353;
int n,k,dp[2][1001000];
int main(){
int i,j,now=0;
scanf("%d%d",&n,&k);
for(i=1;i<=n;i++)dp[now][i]=1;
for(i=2;i<=k;i++){
now^=1;
memset(dp[now],0,sizeof(dp[now]));
for(j=1;j*2<=n;j++)
dp[now][j*2]=(dp[now][j*2]+dp[now^1][j])%mod;
for(j=2;j<=n;j++)
dp[now][j]=(dp[now][j]+dp[now][j-1])%mod;
}
printf("%d
",dp[now][n]);
return 0;
}