嘘~ 正在从服务器偷取页面 . . .

UOJ66 新年的巧克力棒 题解


UOJ66 新年的巧克力棒 题解

题目链接:#66. 新年的巧克力棒

题意:马上就要到羊年了,羊村一片欢腾,懒羊羊则懒洋洋地躺在草坪上吃新年的巧克力棒。

他手上的巧克力棒是个由 $n$ 个巧克力单元格组成的长度为 $n$ 的长条,现在懒羊羊想把巧克力棒掰开成一个个小单元格。

初始时懒羊羊会把这根巧克力棒丢在草坪上,然后每次懒羊羊会从草坪上拿起一根长度大于 $1$ 的巧克力棒,然后从某两个相邻的单元格的间隙处掰开变成两根巧克力棒,然后把这两根巧克力棒丢在草坪上。懒羊羊初始愉悦值为 $0$,每次掰开巧克力棒后如果这两根巧克力棒长度相等,那么懒羊羊将提升 $1$ 点愉悦值。

当然,草坪上全是长度为 $1$ 的巧克力棒时懒羊羊就会停止操作。现在懒羊羊想知道,他能获得的愉悦值最多是多少?

设 $f_i$ 表示长度为 $i$ 的巧(áo)克(lì)力(gèi)能获得的最大价值,则

然后这东西是 $O(n^2)$ 的,看上去也没什么能优化的

注意到有 $n \le 10^3$ 的部分分,说明我们推的柿子是大概率正确的

好像没什么思路,但是这个 $n\le 10^9$ 印发了我们的好奇心(确信

然后打打表试试,打表代码如下:

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iomanip>
#include <random>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define N (int)(1005)

int f[N];
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    for(int i=2; i<=100; i++)
        for(int j=1; j<i; j++)
            f[i]=max(f[i],f[j]+f[i-j]+(j==i-j));
    for(int i=1; i<=20; i++)
        cout << i << " " << f[i] << '\n';
    return 0;
}

表:

1 0
2 1
3 1
4 3
5 3
6 4
7 4
8 7
9 7
10 8
11 8
12 10
13 10
14 11
15 11
16 15
17 15
18 16
19 16
20 18

观察到 $1,2,4,8$ 都减了 $1$ ,而 $6,10$ 减了 $2$

前面这个又是 $2$ 的次幂,难道是??

答案确实是 $n - \text{popc}(n)$ ,这里的 $\text{popc}(n)$ 表示 $n$ 在二进制下的 $1$ 的个数

于是超短码就出现啦:

#include <cstdio>
signed main()
{
    int x,y; 
    for(scanf("%d",&x); x--;)
        scanf("%d",&y),printf("%d\n",y-__builtin_popcount(y));
    return 0;
}

至于为什么答案是这个,可以看看这里的证明 link


文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录