[BZOJ2036]聪明的阿卑多

[BZOJ2036]聪明的阿卑多

试题描述

也许你从没听说过阿卑多,但你一定知道他爷爷的爷爷的爷爷,那就是聪明绝顶的阿凡提先生。是的,阿卑多也是个聪明的小孩。 一天,阿卑多骑着他的小毛驴,在小镇上晃悠,正好遇上了小巴依——那个自以为是的小财主。小巴依正在炫耀他的金币: “你们见过这样的金币么?这可不是一般的金币,你看它们多大多重啊!最主要的是,它们每个上面都刻有我的名字和一个编号,是独一无二的!看看,从我出生开始,每 \(2\) 个月,爸爸便给我 \(1\) 个特做的大金币,并从 \(1\) 开始编号,现在我已经有 \(60\) 枚了,哈哈……” 小巴依见了阿卑多,于是便想考一考他:“阿卑多,听说你是最聪明的。看见我每个金币上的数字了吗?你现在拿取一半的金币,并能用你拿的若干金币上的数的和表示我的任意一枚金币上的数。如果你能办到,那么就奖你一枚金币;如果不能,就给我做三年长工好了。” 阿卑多想了一想,说:“我可以只拿 \(\frac{1}{10}\) 就办到,不过如果我办到了,你就得分一半金币给我。” \(\frac{1}{10}\)?小巴依心想,你准备给我当长工好了。 于是阿卑多开始取金币…… 自然,阿卑多出色的完成了任务,得到了 \(30\) 枚金币,同样的,他把这些金币都分给了穷人们。 给你的任务就不同了。

输入

一个数 \(n(1 \le n \le 1000\) 表示金币枚数(金币上的数分别为 \(1\)\(n\)

输出

两个数,阿卑多最少要拿的金币数以及不同的方案数。

输入示例
6
输出示例
3 2
数据规模及约定

见“输入

题解

首先第一问显然可以贪心做(受二进制的启发)。

第二问其实也是基于这个思想,我们从小到大依次选数,如果已经选的数之和加 \(1\) 大于等于当前要选的数,就可以选这个数。第一问我们已经解决了,步数肯定不会超过 \(logn\),所以可以将它设进 dp 状态里:\(f(i, s, m)\) 表示已选 \(i\) 个数,当前总和是 \(s\),选出的所有数都严格小于 \(m\) 的方案数,然后就可以 dp 啦(注意 \(s\) 在超过 \(n\) 的时候和 \(n\)\(min\) 就好了)。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;
#define rep(i, s, t) for(int i = (s); i <= (t); i++)
#define dwn(i, s, t) for(int i = (s); i >= (t); i--)

int read() {
    int x = 0, f = 1; char c = getchar();
    while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
    while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
    return x * f;
}

#define maxn 1010
#define maxlog 11

int n, step, f[maxlog][maxn][maxn];

int main() {
    n = read();
    
    int sum = 0;
    rep(i, 1, n) if(sum < i) sum += i, step++;
    printf("%d ", step);
    f[0][0][1] = 1;
    rep(i, 0, step) rep(s, 0, n) rep(mx, 1, n) if(f[i][s][mx]) {
        if(mx <= s + 1 && i < step) f[i+1][min(s+mx,n)][mx+1] += f[i][s][mx];
        f[i][s][mx+1] += f[i][s][mx];
    }
    printf("%d\n", f[step][n][n+1]);
    
    return 0;
}

转载于:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/7807907.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值