• uoj 66 新年的巧克力棒 数学


    #66. 新年的巧克力棒

    Time Limit: 20 Sec  Memory Limit: 256 MB

    题目连接

    http://uoj.ac/problem/66

    Description

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

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

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

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

    Input

    一行一个正整数 T。

    接下来 T 行,每行一个正整数 n 表示巧克力棒的长度,你需要对每个给出的 n 计算最多能获得的愉悦值。

    Output

    T 行每行一个整数,表示懒羊羊最多能获得的愉悦值。

    Sample Input

    5
    1
    3
    4
    7
    233333333

    Sample Output

    0
    1
    3
    4
    233333319

    HINT

    题意

    题解:

    其实这道可以打表+猜的,还是比较简单猜出来(个鬼!

    官方题解:

    算法一

    有20分的数据巧克力棒长度非常小,直接搜索下或者手算就行了。
    算法二

    对于 n≤1000,我们可以用 DP 解决。 f[i]=max(f[k]+f[i−k]+[k==i−k])。[k=i−k] 表示 k=i−k 时为 1 否则为 0。时间复杂度 O(n2),可以通过前 5 个点获得 50 分。
    不靠谱的正解

    你需要打个表,然后找规律,就能发现答案是 n−c(n),其中 c(n) 是 n 的二进制表示中 1 的个数。然后就 AC 了!
    靠谱的正解

    我们用数学归纳法证明上述结论。我们按二进制中 1 的个数归纳。

    对于只有一个 1,那么 n=2k,k 是某个正整数,那么显然应该每次折半,递推式是 f[n]=f[n/2]×2+1,解得 f[2k]=2k−1,只损失了1。

    现在假设对于 1 的个数比 c(n) 少的都满足这个性质。

    我们要证明,对于 1 的个数多于 1 个的时候,我们找到最低位的 1,假设在第 j 位,然后把 n 拆成 2j 和 n−2j,这是最优的。

    根据归纳假设,我们只用看怎样能获得更少的 1。我们考虑两个数的加法,可以看作是先分别拆成 2 的整数次幂之和,然后每次找到两个相同的 2k 合并成一个 2k+1。在这个过程中 1 的个数显然是在减少的,所以对于任意 i 均有 c(n)≤c(i)+c(n−i)。而当 i=2j 时可以取到等号,所以这就证明了这个算法的正确性。

    代码:

    //qscqesze
    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <ctime>
    #include <iostream>
    #include <algorithm>
    #include <set>
    #include <vector>
    #include <sstream>
    #include <queue>
    #include <typeinfo>
    #include <fstream>
    #include <map>
    #include <stack>
    typedef long long ll;
    using namespace std;
    //freopen("D.in","r",stdin);
    //freopen("D.out","w",stdout);
    #define sspeed ios_base::sync_with_stdio(0);cin.tie(0)
    #define maxn 200001
    #define mod 10007
    #define eps 1e-9
    int Num;
    char CH[20];
    //const int inf=0x7fffffff;   //нчоч╢С
    const int inf=0x3f3f3f3f;
    /*
    
    inline void P(int x)
    {
        Num=0;if(!x){putchar('0');puts("");return;}
        while(x>0)CH[++Num]=x%10,x/=10;
        while(Num)putchar(CH[Num--]+48);
        puts("");
    }
    */
    inline ll read()
    {
        ll x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    inline void P(int x)
    {
        Num=0;if(!x){putchar('0');puts("");return;}
        while(x>0)CH[++Num]=x%10,x/=10;
        while(Num)putchar(CH[Num--]+48);
        puts("");
    }
    //**************************************************************************************
    
    
    int main()
    {
        //freopen("test.txt","r",stdin);
        int t=read();
        while(t--)
        {
            int a=read();h
            int ans=a;
            while(a)
            {
                a-=a&(-a);
                ans--;
            }
            printf("%d
    ",ans);
        }
    }

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

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

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

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

  • 相关阅读:
    linux 批量替换内容
    在Linux下如何查CC攻击?
    mysql init_connect
    利用javascript对字符串加密
    js学习笔记10----字符串的基本操作
    js学习笔记9----时间操作
    3种方法实现列表自动滚动
    如何解决wow.js与fullpage的兼容性
    js兼容获取元素的样式
    用php去除bom头
  • 原文地址:https://www.cnblogs.com/qscqesze/p/4515594.html
Copyright © 2020-2023  润新知