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+1是2的次方有要求。

但是对于每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/2和n/2+1只有当大量出现n%2等于0了才能每次截掉一半。但是如果四个一组的话,每次长度变成1/4,但是最多生成n/4和n/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\n", ans);
    }
    return 0;
}

代码:(四分)

#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\n", ans);
    }
    return 0;
}

时间: 2024-11-08 00:14:06

ACM学习历程—HDU5587 Array(数学 && 二分 && 记忆化 || 数位DP)(BestCoder Round #64 (div.2) 1003)的相关文章

(BestCoder Round #64 (div.2))Array -- BestCoder Round #64 (div.2)

BestCoder Round #64 (div.2) Array 问题描述 Vicky是个热爱数学的魔法师,拥有复制创造的能力. 一开始他拥有一个数列{1}.每过一天,他将他当天的数列复制一遍,放在数列尾,并在两个数列间用0隔开.Vicky想做些改变,于是他将当天新产生的所有数字(包括0)全加1.Vicky现在想考考你,经过100天后,这个数列的前M项和是多少?. 输入描述 输入有多组数据. 第一行包含一个整数T,表示数据组数.T. \left( 1 \leq T \leq 2 * {10}^

ACM学习历程—HDU5585 Numbers(数论 || 大数)(BestCoder Round #64 (div.2) 1001)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5585 题目大意就是求大数是否能被2,3,5整除. 我直接上了Java大数,不过可以对末尾来判断2和5,对所有位的和来判断3. 代码就不粘了.

ACM学习历程—CodeForces 176B Word Cut(字符串匹配 &amp;&amp; dp &amp;&amp; 递推)

Description Let's consider one interesting word game. In this game you should transform one word into another through special operations. Let's say we have word w, let's split this word into two non-empty parts x and y so, that w = xy. A split operat

【记忆化搜索】Codeforces Round #295 (Div. 2) B - Two Buttons

题意:给你一个数字n,有两种操作:减1或乘2,问最多经过几次操作能变成m: 随后发篇随笔普及下memset函数的初始化问题.自己也是涨了好多姿势. 代码 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #define INF 0x7fffffff; 6 using namespace std; 7 int DP[20100], vis[2010

ACM学习历程—UESTC 1226 Huatuo&#39;s Medicine(数学)(2015CCPC L)

题目链接:http://acm.uestc.edu.cn/#/problem/show/1226 题目就是构造一个对称的串,除了中间的那个只有1个,其余的两边都是对称的两个,自然答案就是2*n-1. 代码: #include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <algorithm> #

ACM学习历程—HDU 4726 Kia&#39;s Calculation( 贪心&amp;&amp;计数排序)

DescriptionDoctor Ghee is teaching Kia how to calculate the sum of two integers. But Kia is so careless and alway forget to carry a number when the sum of two digits exceeds 9. For example, when she calculates 4567+5789, she will get 9246, and for 12

ACM学习历程—HDU 5023 A Corrupt Mayor&#39;s Performance Art(广州赛区网赛)(线段树)

Problem Description Corrupt governors always find ways to get dirty money. Paint something, then sell the worthless painting at a high price to someone who wants to bribe him/her on an auction, this seemed a safe way for mayor X to make money. Becaus

HUD 1501 Zipper(记忆化 or DP)

Problem Description Given three strings, you are to determine whether the third string can be formed by combining the characters in the first two strings. The first two strings can be mixed arbitrarily, but each must stay in its original order. For e

hdu 4960 记忆化搜索 DP

Another OCD Patient Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 490    Accepted Submission(s): 180 Problem Description Xiaoji is an OCD (obsessive-compulsive disorder) patient. This morni