博客园 首页 私信博主 显示目录 隐藏目录 管理 动画

题解 [51nod1201] 整数划分

题面

解析

首先,因为是不同的数字,

可以从小到大依次枚举加上每一个数字的贡献,再枚举每个数.

然而这样会T掉...

考虑到\(n\)只有\(50000\),

当分成的数最多时,设最大的数为\(m\),

\(1+2+3...+m<=n\),

所以最多只会分成315个数(\(m<316\)).

那么设\(f[j][i]\)表示把\(j\)分成\(i\)个数的方案数.

依次枚举加上的数\(i\),

那么这个\(i\)要么作为单独的一块加上去,

要么就分成\(i\)块给之前的贡献过的每个数加1.

所以转移方程:\(f[j][i]-f[j-i][i-1]+f[j-i][i]\).

最后\(ans=\sum_{i=1}^{315}f[n][i]\).

code(可能代码里面有一些时候大于了315别在意):

#include <iostream>
#include <cstdio>
#include <cstring>
#define filein(a) freopen(a".cpp","r",stdin)
#define fileout(a) freopen(a".cpp","w",stdout);
using namespace std;

inline int read(){
	int sum=0,f=1;char c=getchar();
	while((c<'0'||c>'9')&&c!=EOF){if(c=='-') f=-1;c=getchar();}
	while(c>='0'&&c<='9'&&c!=EOF){sum=sum*10+c-'0';c=getchar();}
	return sum*f;
}

const int N=50001;
const int Mod=1000000007;
int n,f[N][401];

int main(){
	n=read();f[1][1]=1;
	for(int i=1;i<=320;i++){
		for(int j=i+1;j<=n;j++) f[j][i]=(f[j-i][i]+f[j-i][i-1])%Mod;
	}
	int ans=0;
	for(int i=1;i<=320;i++) ans=(ans+f[n][i])%Mod;
	printf("%d\n",ans);
	return 0; 
}

posted @ 2019-08-25 19:43  Hastin  阅读(156)  评论(0编辑  收藏  举报