zoukankan      html  css  js  c++  java
  • ACM学习历程—HDU5587 Array(数学 && 二分 && 记忆化 || 数位DP)(BestCoder Round #64 (div.2) 1003)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5587

    题目大意就是初始有一个1,然后每次操作都是先在序列后面添加一个0,然后把原序列添加到0后面,然后从0到末尾,每一个都加上1

    例如:a0, a1, a2 => a0, a1, a2, 1, a0+1, a1+1, a2+1

    题解中是这么说的:“

    其实Ai为i二进制中1的个数。每次变化A{k+2^i}=A{k}+1,(k<2^​i​​)不产生进位,二进制1的个数加1。然后数位dp统计前m个数二进制1的个数,计算每一位对答案的贡献。只需考虑该位填1,其高位与低位的种数即可。

    不过我没有想到这个。

    我写了几次变换后,发现:

    对最前面添加一个0

    于是每次变换长度都变成两倍,而且前后序列每一个对应差值为1

    不过这样前后二分显然对于m+12的次方有要求。

    但是对于每2个组成一组,那么发现,至少每次变换都是以2的倍数个变换的。

    也就是说单看i%2== 1的那些数ai,发现他们组成的序列变换和原序列一模一样。

    i%2== 0的同理,不过需要在每一个数的基础上加上1

    然后对于s(n),自然可以由它前面i%2 == 1, i%2 == 0的两组序列构成

    于是就变成了s(n) = s(n/2)+s(n/2)+n/2 or s(n/2+1)+s(n/2)+n/2(取决于n%2

    这样的话就能二分下去了,不过需要记忆化,这里采用了map进行记忆化。

    不过比赛的时候,我写的是四个为一组。由于上面的n/2n/2+1只有当大量出现n%2等于0了才能每次截掉一半。但是如果四个一组的话,每次长度变成1/4,但是最多生成n/4n/4+1。不过这两种在不记忆化的情况下都会T

    不过用map记忆化后,我怕会MLE,本地测了好几组数据,都没有占很大内存。

    代码:(二分)

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    #include <cstring>
    #include <algorithm>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    #define LL long long
    
    using namespace std;
    
    LL m;
    map<LL, LL> s;
    
    LL dfs(LL n)
    {
        if (n == 1) return 0;
        if (n == 2) return 1;
        LL ans, t1 = 0, t2;
        if (n%2)
        {
            if (s[n/2+1] == 0)
            {
                t1 = dfs(n/2+1);
                s[n/2+1] = t1;
            }
            else t1 = s[n/2+1];
        }
        if (s[n/2] == 0)
        {
            t2 = dfs(n/2);
            s[n/2] = t2;
        }
        else t2 = s[n/2];
    
        ans = (n%2)*t1+(2-n%2)*t2;
        ans += n/2;
        return ans;
    }
    
    int main()
    {
        //freopen("test.in", "r", stdin);
        int T;
        scanf("%d", &T);
        for (int times = 1; times <= T; ++times)
        {
            scanf("%I64d", &m);
            LL ans;
            ans = dfs(m+1);
            printf("%I64d
    ", ans);
        }
        return 0;
    }
    View Code

    代码:(四分)

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    #include <cstring>
    #include <algorithm>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    #define LL long long
    
    using namespace std;
    
    LL m;
    map<LL, LL> s;
    
    LL dfs(LL n)
    {
        if (n == 1) return 0;
        if (n == 2) return 1;
        if (n == 3) return 2;
        if (n == 4) return 4;
        LL ans, t1 = 0, t2;
        if (n%4)
        {
            if (s[n/4+1] == 0)
            {
                t1 = dfs(n/4+1);
                s[n/4+1] = t1;
            }
            else t1 = s[n/4+1];
        }
        if (s[n/4] == 0)
        {
            t2 = dfs(n/4);
            s[n/4] = t2;
        }
        else t2 = s[n/4];
        ans = (n%4)*t1+(4-n%4)*t2;
        ans += n/4*4;
        if (n%4) ans += n%4-1;
        return ans;
    }
    
    int main()
    {
        //freopen("test.in", "r", stdin);
        int T;
        scanf("%d", &T);
        for (int times = 1; times <= T; ++times)
        {
            //s.clear();
            scanf("%I64d", &m);
            LL ans;
            ans = dfs(m+1);
            printf("%I64d
    ", ans);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    Python-手动安装第三方包
    SQL SERVER-根据jobID查job
    python-包模块等概念
    锁表
    Python-try异常捕获
    胶水语言
    C++之多态性与虚函数
    android
    开源许可协议
    hal
  • 原文地址:https://www.cnblogs.com/andyqsmart/p/5003587.html
Copyright © 2011-2022 走看看