zoukankan      html  css  js  c++  java
  • poj3252 Round Numbers

    poj3252 Round Numbers

    组合数学(数位dp)

    (没想到书上的标程还要看脸TAT)

    (我以后再也不在poj上用scanf/printf了TAT)

    (poj的题都默认多组数据的吗TAT)

    tips:信息学奥赛数学一本通的标程和部分Baidu上的代码访问数组越界,脸黑的会GG(比如我QAQ),详细见下

    题意:求闭区间[a,b]内有多少个数转换成二进制后0的个数比1多,1<=a<b<=2*(10^9)

    显然是数位dp的套路: solve(b+1)-solve(a) (本题的solve(n)不包括n)

    于是我们解决的范围就变成 [0,n] 了

    先把n转成二进制(灰常显然),扔到数组wt里

    蓝后我们分类讨论

    1.所求数的长度<n的长度

    我们可以用组合数直接算出。(可以预处理)

    枚举所求数的长度 i=1 to len-1-1 (第一位一定是1所以多扣一位)

    再枚举所求数中0的个数 j= i/2+1 to i ,累加C( i , j )就完事了

    2.所求数的长度==n的长度

    我们把wt数组拿来从高位到低位枚举 i= len-1 to 1 (∵↑↑ ∴len-1)

    当 wt[i]==0时,我们用变量 z 统计 0的个数

    当 wt[i]==1时:

    我们先假定该位为0,那么接下来的若干位无论怎么排都严格小于n

    ∴也可以枚举0的个数用组合数瞎搞

    j= max(0,(len+1)/2-(z+1)) to i-1

    attention:取max防止数组越(负)界(标程的锅就在这)

    最后累加答案,end.

    use 2h30min,6 submissions TAT

    #include<iostream>
    using namespace std;
    int max(int a,int b) {return a>b ?a:b;}
    int wt[35],a,b,c[35][35];
    int solve(int n){
        int res=0,z=0,len=0;
        for(;n;n>>=1) wt[++len]=(n&1); //转二进制
        for(int i=1;i<len-1;++i) //长度<n
            for(int j=i/2+1;j<=i;++j)
                res+=c[i][j];
        for(int i=len-1;i>=1;--i) //长度==n
            if(wt[i]){
                for(int j=max(0,(len+1)/2-z-1);j<i;++j)
                    res+=c[i-1][j];
            }else ++z;
        return res;
    }
    int main(){
        for(int i=0;i<=32;++i)//组合数预处理
            for(int j=0;j<=i;++j)
                c[i][j]=(!j||i==j)?1:c[i-1][j-1]+c[i-1][j];
        while(cin>>a>>b) cout<<solve(b+1)-solve(a)<<endl;
        return 0;
    }
  • 相关阅读:
    Handbook of Document Image Processing and Recognition文档图像处理与识别手册 前言&目录
    An Overview of Symbol Recognition符号识别综述
    Resnet
    python detect.py
    pytorch训练模型
    如何有效使用Pretrained Models
    SOLID原则 【转】
    vi编辑器
    linux基础知识 【转】
    linux 常用命令1【转】
  • 原文地址:https://www.cnblogs.com/kafuuchino/p/9784510.html
Copyright © 2011-2022 走看看