【传送门:51nod-1259】
简要题意:
将n分成若干个整数相加,求出方案数
题解:
DP
和上一题不同,分成的整数可以相等,那么就不能用上一题的DP直接做,但可以利用它的思想
我们将n分成(1,sqrt(n))和(sqrt(n)+1,n)两部分来处理
首先对于第一部分,我们直接暴力背包求出s1[i]表示构成i的方案数
因为>sqrt(n)的数最多只会出现sqrt(n)次,所以我们依然可以用上一题的想法来O(n*sqrt(n))来做
f[i][j]表示用i个数组成j的方案
转移方式:
1.整体+1
2.加上一个数sqrt(n)+1
最后用数组s2[i]表示第二部分中构成i的方案数
然后答案就是∑s1[i]*s2[n-i]
参考代码:
#include<cstdio> #include<cstdlib> #include<cmath> #include<algorithm> #include<cstring> using namespace std; typedef long long LL; int Mod=1e9+7; int f[310][51000]; int s1[51000],s2[51000]; int main() { int n; scanf("%d",&n);int m=int(sqrt(double(n)))+1; s1[0]=1; for(int i=1;i<m;i++) { for(int j=i;j<=n;j++) { s1[j]=((LL)s1[j]+(LL)s1[j-i])%Mod; } } f[0][0]=1;s2[0]=1; for(int i=1;i<=m;i++) { for(int j=m;j<=n;j++) { f[i][j]=((LL)f[i][j-i]+(LL)f[i-1][j-m])%Mod; s2[j]=((LL)s2[j]+(LL)f[i][j])%Mod; } } int ans=0; for(int i=0;i<=n;i++) ans=((LL)ans+(LL)s1[i]*s2[n-i])%Mod; printf("%d ",ans); return 0; }