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