题目大意
给定一个信封,最多只允许粘贴 N N N张邮票,计算在给定 K ( N + K ≤ 15 ) K(N+K≤15) K(N+K≤15)种邮票的情况下(假定所有的邮票数量都足够),如何设计邮票的面值,能得到最大值 M A X MAX MAX,使在 1 1 1至 M A X MAX MAX之间的每一个邮资值都能得到。
思路
一开始并没有啥思路,然后瞎想另一个问题,给定的k个数,最多使用n个,求 M A X MAX MAX该要怎么求。然后发现这个问题可以用 d p dp dp来解决, d p [ i ] dp[i] dp[i]代表 i i i最少使用多少个数字组成,那么转移方程为 m i n ( d p [ i − j ] + d p [ j ] ) , i > = j min(dp[i-j]+dp[j]),i>=j min(dp[i−j]+dp[j]),i>=j,这里是可以优化的 m i n ( d p [ i − k j ] ) + 1 , k j min(dp[i-k_j])+1,k_j min(dp[i−kj])+1,kj为所选择的某个数,为啥可以这样,也很简单,这几种情况必定包含了第一种的所有情况,而且可以发现相邻的 d p [ i ] dp[i] dp[i]最大差 1 1 1。
然后我们就可以 d f s dfs dfs枚举所选择的数,然后 d p dp dp来求 M A X MAX MAX。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int INF = 0x3f3f3f3f;
const double Pi = acos(-1);
namespace {
template <typename T> inline void read(T &x) {
x = 0; T f = 1;char s = getchar();
for(; !isdigit(s); s = getchar()) if(s == '-') f = -1;
for(; isdigit(s); s = getchar()) x = (x << 3) + (x << 1) + (s ^ 48);
x *= f;
}
}
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define _for(n,m,i) for (register int i = (n); i < (m); ++i)
#define _rep(n,m,i) for (register int i = (n); i <= (m); ++i)
#define _srep(n,m,i)for (register int i = (n); i >= (m); i--)
#define _sfor(n,m,i)for (register int i = (n); i > (m); i--)
#define lson rt << 1, l, mid
#define rson rt << 1 | 1, mid + 1, r
#define lowbit(x) x & (-x)
#define pii pair<int,int>
#define fi first
#define se second
const int N = 51000;
int n, k;
int dp[N], an[20], a[20], ans = 0, cnt;
int solve(int k) {
dp[0] = 0;
int len = 1;
while(1) {
int Max = INF;
for(int i = 0; i < k; i++) {
if(len-a[i] < 0) break;
Max = min(Max, dp[len-a[i]]);
}
dp[len] = Max + 1;
if(dp[len] >= n+1) break;
len++;
}
return len;
}
void dfs(int step) {
if(step >= k) {
dp[0] = 0;
int len = solve(k);
if(len > ans) {
ans = len;
for(int i = 0; i < k; i++) an[i] = a[i];
}
return;
}
int r = solve(step);
for(int i = a[step-1]+1; i <= r; i++) {
a[step] = i;
dfs(step+1);
}
}
int main() {
read(n); read(k);
a[0] = 1;
dfs(1);
for(int i = 0; i < k; i++) {
printf("%d%c", an[i], " \n"[i==k-1]);
}
printf("MAX=%d\n", ans-1);
}