6.12 考试 + 总结

T1 celebration

  • 题目大意 把n分成每个大小不同的正整数的方案数,有序

  • 我们可以先求出无序的数量,再乘一下阶乘就可以了

    • 考试时比较无脑,多开了一位状态,f[i][j][0]表示把i分成j个不同的数并且最小的树不为1的方案数,f[i][j][1]代表最小的数为1的方案数

      • 这样dp状态,f[i][j][0] = f[i-j][j][0]+f[i-j][j][1], f[i][j][1] = f[i-1][j-1][0];
    • 其实可以去掉最后一维,f[i][j] = f[i-j]j+f[i-1-(j-1)]j-1;

    • 题解还给了另外一种做法,我们首先给每块分配给i的大小,然后把剩下的数分成若干个1~m的数,每一个被划分出来的数相当于给(n-i+1,n)的数同时加1,这样保证了递增,而且可以覆盖所有的情况


#define MAXN 100010UL
#include <cstdio>
#define Mod 998244353

using namespace std;

int n, m, f[2][MAXN][2];

int main() {
	freopen("celebration.in", "r", stdin);
	freopen("celebration.out", "w", stdout);
	scanf("%d%d", &n, &m);
	if(1ll*m*(m+1)>2*n) {
		printf("0");
		return 0;
	}
	int lt = 1, nw = 0;
	f[0][0][0] = 1;
	for(int i = 1 ; i <= m ; ++ i) {
		lt ^= 1, nw ^= 1;
		int l = (i*(i+1))/2;
		for(int j = 0 ; j < l && j <= n ; ++ j) f[nw][j][0] = f[nw][j][1] = 0;
		for(int j = l ; j <= n ; ++ j) {
			f[nw][j][0] = f[nw][j-i][0]+f[nw][j-i][1];
			if(f[nw][j][0]>=Mod) f[nw][j][0] -= Mod;
			f[nw][j][1] = f[lt][j-1][0];
		}
	}
	int ans = f[nw][n][0]+f[nw][n][1];
	if(ans>=Mod) ans -= Mod;
	for(int i = 1 ; i <= m ; ++ i) ans = 1ll*ans*i%Mod;
	printf("%d", ans);
	return 0;
}    
posted @ 2016-06-12 17:36  assassain  阅读(148)  评论(0编辑  收藏  举报