light oj 1031(数位DP)

求一段区间中,每个十进制数所对应的二进制数中连续的1的个数之和。

设dp[i][0]代表长度为i的二进制数,首位为0,所含有的连续的1的个数之和。

dp[i][1]代表长度为i的二进制数,首位为1,所含有的连续的1的个数之和。

a: d[i][1]=d[i-1][0]+d[i-1][1]+(1<<(i-2));
 b: d[i][0]=d[i-1][0]+d[i-1][1];

这里面有一个需要注意的地方是,假设有一个数字是111,那么它含有2个连续的1,具体体现在

方程上是分两次计算的,一个是a式中的第二项,i位为1,加上长度为i-1的二进制数,首位为1,所含有的连续的1的个数之和,

那么已经算了一次111,另外一个是a式中的第三项,i位和i-1位为1,第i-2位之后任意枚举,这是也计算了一次111.

同理1111也是一样的,初始时d[i][1]=d[i-1][0],一个是a式中的第二项,i位为1,加上长度为i-1的二进制数,首位为1,所含有的连续的1的个数之和,

那么d[i][1]=d[i-1][0]+2,另外一个是a式中的第三项,i位和i-1位为1,第i-2位之后任意枚举,那么d[i][1]=d[i-1][0]+2+1.

d[i][1]=d[i-1][0]+3;所以这里对长度为3以上的连续的1处理是,通过两种方式,叠加处理。

计算时,从高位到低位,按位枚举,如果当前位是1,说明就是上界,i-1位之后可以任意枚举,如果当前位是0,只能当前缀,此时什么都不加。

#include <stdio.h>
#include <iostream>
#include <map>
#include <set>
#include <list>
#include <stack>
#include <vector>
#include <math.h>
#include <string.h>
#include <queue>
#include <string>
#include <stdlib.h>
#include <algorithm>
#define LL long long
using namespace std;
#define maxn 35
LL  d[maxn][maxn];
LL  digit[maxn];
LL  C[maxn][maxn];
void init()
{
    memset(d,0,sizeof(d));
    d[2][1]=1;
   for(int i=3;i<maxn;i++)
     for(int j=0;j<=1;j++)
     {
         d[i][1]=d[i-1][0]+d[i-1][1]+(1<<(i-2));
         d[i][0]=d[i-1][0]+d[i-1][1];
     }

}
LL solve(LL x)
{
    LL len=0,xx=x;
    while(x>0)
    {
        digit[++len]=x%2;
        x>>=1;
    }
     digit[len+1]=0; //初始化前缀为0,0是没有任何影响的,后面一位可能会用到前面一位
      LL ans=0;
      int flag=0;
     for(int i=len;i>=1;i--) //当前位是1,就是上界,i-1位之后可以任意枚举,否则只能当前缀。
    {
          if(digit[i]==1)   //如果当前位是1,i-1位可以任意枚举,如果当前位是0,那么说明是上界
               ans+=d[i-1][0]+d[i-1][1];
          if(flag)
          {
              if(digit[i]==1)  //只有前缀不是上界的时候,才可以任意枚举
                 ans+=flag * ( 1 << (i-1));  //i位填0
          }
          if(flag && (digit[i+1]==1 && digit[i]==1))
          {
               flag++;
          }
          else if(!flag && digit[i+1]==1 && digit[i]==1)
          {
              flag=1;
          }
    }
    return ans;
}
int main()
{
   //  freopen("in.txt","r",stdin);
    // freopen("out.txt","w",stdout);
    int t,Case=0;
    scanf("%d",&t);
    init();
      LL n=0;
    while(t--)
    {
        scanf("%lld",&n);
        printf("Case %d: %lld\n",++Case,solve(n+1));
    }
    return 0;
}

B - Fast Bit Calculations

Time Limit:2000MS     Memory Limit:32768KB     64bit IO Format:%lld & %llu

Submit Status Practice LightOJ 1032

Appoint description:

Description

A bit is a binary digit, taking a logical value of either 1 or 0 (also referred to as "true" or "false" respectively). And every decimal number has a binary representation which is actually a series of bits. If a bit of a number is 1 and its next bit is also 1 then we can say that the number has a 1 adjacent bit. And you have to find out how many times this scenario occurs for all numbers up to N.

Examples:

      Number         Binary          Adjacent Bits

12                    1100                        1

15                    1111                        3

27                    11011                      2

Input

Input starts with an integer T (≤ 10000), denoting the number of test cases.

Each case contains an integer N (0 ≤ N < 231).

Output

For each test case, print the case number and the summation of all adjacent bits from 0 to N.

Sample Input

7

0

6

15

20

21

22

2147483647

Sample Output

Case 1: 0

Case 2: 2

Case 3: 12

Case 4: 13

Case 5: 13

Case 6: 14

Case 7: 16106127360

时间: 2024-11-05 16:01:00

light oj 1031(数位DP)的相关文章

light oj 1068 数位dp

1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 #include <math.h> 5 #include <iostream> 6 #include <algorithm> 7 #include <climits> 8 #include <queue> 9 #define ll long long 10 11 using na

Timus OJ 1057 数位dp

http://acm.timus.ru/problem.aspx?space=1&num=1057 1057. Amount of Degrees Time limit: 1.0 second Memory limit: 64 MB Create a code to determine the amount of integers, lying in the set [X;Y] and being a sum of exactlyK different integer degrees of B.

swust oj 1097--2014(数位dp)

题目链接:http://acm.swust.edu.cn/problem/1097/ Time limit(ms): 1000 Memory limit(kb): 32768 今年是2014年,所以小明喜欢2014的每一位数字(即:2,0,1,4),小明想知道在区间[l,r](包括l和r)中有多少个数中含有这4个数字(数字无前缀零). Description 多组数据. 每组数据输入2个数l,r(0<l<r<=10^9) Input 输出占一行,即区间[l,r](包括l和r)中包含的满足

Light OJ 1031 - Easy Game(区间dp)

题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1031 题目大意:两个选手,轮流可以从数组的任意一端取值, 每次可以去任意个但仅限在一端, 他们的得分分别是取得所有值的和.现在求这两个选手得分差值的最大值. 解题思路:设dp[i][j]代表从i到j这个区间中,所能够得到的最大差值,只需要枚举其中i到j之间的一个数c,作为断电,那么最大值应该为max(sum[c]-sum[i-1]-dp[c+1][j], sum[j]-sum

Light OJ 1031 - Easy Game(区间DP)

题目大意: 给你一个n,代表n个数字,现在有两个选手,选手A,B轮流有有一次机会,每个选手一次可以得到一个或者多个数字,从左侧或者右侧,但是不能同时从两边取数字,当所有的数字被取完,那么游戏结束.然后计算每个选手所得到数字的总和,每个选手都尽量让自己的分数比较多,选手A先开始取数.假设每个选手取得数字都是最优的,问A最多比B多多少分数,. 题目分析: 记忆化搜索,区间DP. dp[该谁取了][左区间L][右区间] = 所能取到的最大值. 做下简单的预处理,得到区间L-R之间的和. 然后状态转移

light oj 1084 线性dp

1 #include <iostream> 2 #include <algorithm> 3 #include <cstring> 4 #include <cstdio> 5 #include <queue> 6 #define ll long long 7 8 using namespace std; 9 const int N = 1e5+1000; 10 11 int a[N],dp[N]; 12 13 void solve() 14 {

light oj 1422 区间dp

1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 #include <math.h> 5 #include <iostream> 6 #include <algorithm> 7 #include <climits> 8 #include <queue> 9 #define ll long long 10 11 using na

Light oj 1030 概率DP

D - Discovering Gold Crawling in process... Crawling failed Time Limit:2000MS     Memory Limit:32768KB     64bit IO Format:%lld & %llu Submit Status Practice LightOJ 1030 Description You are in a cave, a long cave! The cave can be represented by a 1

Light OJ 1032 - Fast Bit Calculations(数位DP)

题目大意: 一个数字把他看成二进制数字,数字里又会一些相邻的1,问从0到n至间所有相邻1的总和是多少? 分解成2进制数字,然后数位DP就行了. ======================================================================== #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<