Problem A: Partitioning for fun and profit
A partition of a positive integer number m into n elements ( n ≤ m ) is a sequence of positive numbers a1 ,..., an such that a1 +...+ an = m and a1 ≤ a2 ≤ ... ≤ an . Your task is to find a partition of a number m which occupies the k -th position in the lexicographically ordered sequence of all partitions of m into n elements.The lexicographic ordering among the partitions of a number is defined as follows. For two partitions a and bof m into n elements such that a = [a1,...,an] andb = [b1,...,bn] we have a < b if and only if there exists an 1 ≤ i ≤ n such that for all j < i we have aj = bj and ai < bi. The sequence of all partitions is ordered in increasing lexicographic order and at the first we have the following sequence 1, 1, ... 1, m-n+1.
The first line of input contains a number c giving the number of cases that follow. Each of the subsequent clines contains three numbers: 1 ≤ m ≤ 220, 1 ≤ n ≤ 10 and 1 ≤ k which is not bigger than the number of partitions of m into n elements.
For each input data set print the k-th partition of m into n elements. Each element of a partition is to be printed in a separate line.
Sample input
2 9 4 3 10 10 1
Output for sample input
1 1 3 4 1 1 1 1 1 1 1 1 1 1
Author: Adapted from VI AMPwPZ by P. Rudnicki
思路:首先预处理一下,用dp[i][j][k]表示拆分的和为i,拆分为j组,而且第一个数k的情况数。转移的时候就是dp[i+x][j+1][x] += dp[i][j][k] (x <= k) 。 求了一遍之后,预处理k的前缀和 , dp[i][j][k]就是 第一个数>=k的情况数了。 详细请看代码
代码:
#include <iostream>
#include <vector>
#include <algorithm>
#include <string.h>
#include <cstring>
#include <map>
#include <set>
#include <stdio.h>
#include <cmath>
#include <cassert>
#include <math.h>
#define rep(i,a,b) for(int i=(a);i<(b);++i)
#define rrep(i,b,a) for(int i = (b); i >= (a); --i)
#define clr(a,x) memset(a,(x),sizeof(a))
#define LL long long
#define eps 1e-9
#define mp make_pair
using namespace std;
const int maxn = 220 + 5;
LL dp[maxn][11][maxn];
int n,m;
LL K;
void pre_init()
{
dp[1][1][1] = 1;
rep(i,1,maxn-1) {
dp[i][1][i] = 1;
rep(j,1,10) {
rep(k,1,i+1) {
rep(x,1,k+1) {
if (i + x >= maxn) break;
dp[i+x][j+1][x] += dp[i][j][k];
}
}
}
}
rep(i,0,maxn) {
rep(j,0,11) {
rrep(k,maxn-2,0) {
dp[i][j][k] += dp[i][j][k+1];
}
}
}
}
int ans[maxn];
void solve()
{
ans[0] = 1;
rep(i,1,n) {
int j;
for(j = ans[i-1]; j <= m; ++j) {
m -= j;
if (dp[m][n-i][j] >= K) break;
K -= dp[m][n-i][j];
m += j;
}
ans[i] = j;
}
ans[n] = m;
rep(i,1,n+1) printf("%d\n",ans[i]);
}
int main()
{
//Getinput(); return 0;
#ifdef ACM
// freopen("in.txt", "r", stdin);
// freopen("out.txt","w",stdout);
#endif // ACM
pre_init();
int T; cin >> T;
rep(cas,1,T+1) {
scanf("%d%d%lld",&m,&n,&K);
solve();
}
}