数位统计Bestcoder18

F.A.Q
Hand In Hand
Online Acmers
Forum | Discuss
Statistical Charts
Problem Archive
Realtime Judge Status
Authors Ranklist
 
      C/C++/Java Exams     
ACM Steps
Go to Job
Contest LiveCast
ICPC@China
Best Coder beta
VIP | STD Contests
Virtual Contests 
    DIY | Web-DIY beta
Recent Contests
Author ID 
Password 
  Register new ID

Bits Problem

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 186    Accepted Submission(s): 46


Problem Description
If the quantity of '1' in a number's binary digits is n, we call this number a n-onebit number. For instance, 8(1000) is a 1-onebit number, and 5(101) is a 2-onebit number. Now give you a number - n, please figure out the sum of n-onebit number belong to [0, R).
 

Input
Multiple test cases(less than 65). For each test case, there will only 1 line contains a non-negative integer n and a positive integer   R(n1000,0<R<21000) , R is represented by binary digits, the data guarantee that there is no leading zeros.
 

Output
For each test case, print the answer module 1000000007 in one line.
 

Sample Input
      
      
1 1000
 

Sample Output
      
      
7
 

Source


  比如13,1101,假设要求含3个1的个数,就等于紫色区域3个1的个数加上绿色区域2个1的个数加上紫色区域1个1的个数,如果这条路径本身满足则还要加1。


  先初始化,用f[i][j]表示高度为i的完全二叉树的数中二进制恰好有j个1的数的个数,则有f[i][j]=f[i-1][j]+f[i-1][j-1]。
  然后从31位循环到第1位(如果此时路径上的1已经超过要求就退出循环),用k表示目前已经路径上已经有几个1。如果这一位是1,就k++,并且把这一位变成0。如果下一位是1,就需要加上以这一位为根的左子树上满足k-K(K是题目要求的1)个1的个数。

这个题求得是所有数的和,如果当前位是1则要把跟他平级的左子树的所有情况的值都加上。

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=1010;
const int MOD=1000000007;
LL C[maxn][maxn],W[maxn];
int N;
char s[maxn];
void init()
{
    memset(C,0,sizeof(C));
    C[0][0]=C[1][0]=C[1][1]=1;
    for(int i=2;i<maxn;i++)
    {
        C[i][0]=C[i][i]=1;
        for(int j=1;j<i;j++)
            C[i][j]=(C[i-1][j]+C[i-1][j-1])%MOD;
    }
    W[0]=1;
    for(int i=1;i<maxn;i++)
        W[i]=(W[i-1]*2)%MOD;
}
LL f(int len,int cnt)
{
    LL ans=0;
    if(len>=1&&cnt>=1)ans=(W[len]-1)*C[len-1][cnt-1];
    ans=(ans%MOD+MOD)%MOD;
    return ans;
}
int main()
{
    init();
    while(scanf("%d%s",&N,s)!=EOF)
    {
        int len=strlen(s);
        int cnt=0;
        LL tmp=0,ans=0;
        for(int i=0;i<len;i++)
        {
            if(N<cnt)break;
            if(s[i]=='1')
            {
                ans=(ans+C[len-1-i][N-cnt]*tmp%MOD+f(len-1-i,N-cnt))%MOD;
                cnt++;
                tmp=(tmp+W[len-1-i])%MOD;
            }

        }
        printf("%I64d\n",ans);
    }
    return 0;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值