首页 > 其他分享 >poj-3286

poj-3286

时间:2023-05-23 16:02:13浏览次数:49  
标签:int 个数 long num poj 百位数 zeroNum 3286


//stupid method!!!!!!!!!!!!!!!
//388K  360MS   G++
#include <stdio.h>
#include <string.h>
#include <math.h>

int C[33][33]; // C[n][m], choose m from n;

void getCombination() {
    for (int n = 0; n <= 32; n++) {
        for (int m = 0; m <= n; m++) {
            if (m == 0) { // choose nothing
                C[n][m] = 1;
            } else if (n == 0) { // nothing to choose
                C[n][m] = 0;
            } else if (m > n) {
                C[n][m] = 0;
            } else if (m == n) {
                C[n][m] = 1;
            } else {
                C[n][m] = C[n-1][m] + C[n-1][m-1];
                // printf("C %d %d is %d\n",n, m, C[n][m]);
            }
        }
    }
}

char str1[20];
char str2[20];

int getHowManyZero(char * num) {
    int zeroNum = 0;
    int length = strlen(num);
    for (int i = 0; i < length; i++) {
        if (num[i] == '0') {
            zeroNum++;
        }
    }
    return zeroNum;
}

long long getZeroNum(char * num) {
    int length = strlen(num);
    long long totalZeroNum = 1; // 0 has 1 '0'

    // step 1, all value's length < num
    for (int curLength = 1; curLength <= length-1; curLength++) {
        for (int zeroNum = 1; zeroNum <= curLength - 1; zeroNum++) {
            totalZeroNum += zeroNum*
                        C[curLength - 1][zeroNum]*pow(9, curLength - zeroNum);
        }
    }

    // printf("S1 %lld\n", totalZeroNum);

    //step2, all value's length == num's length, first pos val < num's first pos val
    char firstChar = num[0];
    int possibleMostChoose = firstChar - '1';
    if (possibleMostChoose > 0) {
        long long curTotalNum = 0;
        for (int zeroNum = 1; zeroNum <= length-1; zeroNum++) {
            curTotalNum += zeroNum*C[length-1][zeroNum]
                            *pow(9, length-1 - zeroNum);
        }
        totalZeroNum += possibleMostChoose * curTotalNum;
    }

    // printf("S2 %lld\n", totalZeroNum);

    int beforeZeroNum = 0;
    for (int curPos = 1; curPos <= length-1; curPos++) { // from the 2nd char to last char
        char curChar = num[curPos];
        int possibleMostChoose = curChar - '0';

        if (possibleMostChoose > 0) {
            long long curTotalNum = 0;
            if (possibleMostChoose-1 > 0) {            
                for (int zeroNum = 0; zeroNum <= length - curPos -1; zeroNum++) {
                    curTotalNum += (zeroNum + beforeZeroNum)*C[length - curPos -1][zeroNum]
                                *pow(9, length - curPos - 1 - zeroNum);
                }
                totalZeroNum += (possibleMostChoose-1) * curTotalNum;
            }
            
            // for '0'
            curTotalNum = 0;
            if (length - curPos -1 >= 1) {            
                for (int zeroNum = 0; zeroNum <= length - curPos -1; zeroNum++) {
                    curTotalNum += (zeroNum + 1 + beforeZeroNum)*C[length - curPos -1][zeroNum]
                                *pow(9, length - curPos - 1 - zeroNum);
                }
            } else { // last pos
                // curTotalNum +=  (possibleMostChoose-1) * beforeZeroNum;
                curTotalNum += (beforeZeroNum + 1);            
            }
            totalZeroNum += curTotalNum;

        } else if (possibleMostChoose == 0) {
            beforeZeroNum++;
        }
    }

    // printf("S3 %lld\n", totalZeroNum);

    return totalZeroNum;
}

int main() {
    getCombination();
    while(scanf("%s %s", str1, str2) != EOF) {
        // printf("%s %s\n", str1, str2);
        if (str1[0] == '-') {
            return 0;
        }
        long long nZeroNum = getZeroNum(str2);
        int zeroNumEnd = getHowManyZero(str2);
        if (str1[0] != '0') {
            long long mZeroNum = getZeroNum(str1);
            printf("%lld\n", nZeroNum - mZeroNum + zeroNumEnd);
        } else {
            printf("%lld\n", nZeroNum + zeroNumEnd); 
        }
    }
}

用了非常笨的办法来得到0的个数,是从排列组合的角度出发, 对当前数字的每一位进行检查,遍历比起小并且含有0的数,累加0的个数,但是这种朴素的思路会有很多特殊情况,到最后完全就是一堆逻辑的堆砌,十分难看,贴一个容易理解的别人的题解:


From:javascript:void(0)

首先转化成求 [0, x] 中所有数中,含有的 0 的个数

那么对于一个数 x,怎么求出从 0 到 x 中所有数含有 0 的个数的和呢?

我们可以限制每一位是 0,然后再来计算。举个例子,假设 x 是 21035

        首先 0 肯定是一个,sum 赋初值为 1

        个位数是 0

                个位数前面的数不能是 0,能够取的数就是 [1, 2103],个位后面没有了

                那么 sum+=2103*1

        十位数是 0

                十位数前面的数不能是 0,能够取的数就是 [1, 210],由于 0 比 3 小,十位后面可以取 [0, 9]

                那么 sum+=210*10

        百位数是 0

                百位数前面的数不能是 0,能够取的数就是 [1, 21],由于 0 是等于 0 的,这里就要特殊处理下了:

                百位数前面的数如果是在 [1, 20] 中的,百位数后面的数可以取的就是 [0, 99]

                百位数前面的数如果取的是 21,百位数后面的数就只能取 [0, 35]

                那么,sum+=20*100+36

        ......

相信手推到这里了,读者已经能够明白怎么操作

这种思路 细化到每个位,取0时,能够得到的比数N小的数的个数(也就是该位0的个数),然后利用加法原理进行累加,逻辑比较简明,但是还是有特殊情况处理的.


比如算4123中有多少个2

按位统计,,,先算各位,,个位是2的情况有413种,,,因为各位左边可以0~412,,,而右边没有数字,,,

然后是十位,,,十位是2的有41*10 + 1*4种,,当左边从0~40时,,,右边可以从0~9,,,而左边为41时,,右边只能从0~3

然后是百位,,,,百位有4*100种,,,,即左边从0~3,,右边从0~99

千位有  1*1000,,,左边没有数字,,,右边0~999,,,,

上面是计算1~9,,,,计算0的时候比较特殊,,,,原因是除了0这一个数字之外,,,,0不能做开头,,,

可以看到在求1~9的个数的时候,,,都是分为2部分相乘,,,这样0的处理也很简单,,只需把相乘的左半部分-1,,,,



标签:int,个数,long,num,poj,百位数,zeroNum,3286
From: https://blog.51cto.com/u_9420214/6332990

相关文章

  • poj-2282
    //380K 32MS G++#include<stdio.h>#include<string.h>#include<math.h>longlongappearTime1[10];longlongappearTime2[10];voidgetAppearTime(intnum,longlong*appearArray){ appearArray[0]=1; if(num==0){ return; }......
  • poj-2249
    //356K16MSG++//356K0MSG++addm==0check//356K16MSG++//356K0MSG++addm==0check#include<stdio.h>#include<string.h>#include<math.h>intm;intn;//voidgetNum(unsignedintn,unsignedintm){//......
  • poj-1037
    //196K16MSC++#include<cstdio>#include<cstring>usingnamespacestd;constintMAX=25;longlongDP[MAX][MAX][2];//0:down.1:upvoidinit(){for(intcurPlankNum=1;curPlankNum<=20;curPlankNum++){for(......
  • poj-2140
    //132K 110MS C++#include<cstring>#include<cstdio>usingnamespacestd;intN;longlongcnt;voidsolve(intN){ intbegin=1; intend=1; longlongsum=1; while(1){ if(begin>N){ break; } //if(begin==......
  • poj-1988
    //564K 282MS C++#include<cstdio>#include<cstring>#include<iostream>usingnamespacestd;structUF_Node{ intup; intcount; intparent;};typedefstructUF_NodeUF_Node;UF_NodeUF_Array[30001];voidcreat(){ intc; for(......
  • poj-1693
    //136K 0MS C++#include<cstdio>#include<cstring>structLine{ intbx,ex; intby,ey;};typedefstructLineLine;LinehLine[110];LinevLine[110];intcaseNum;intLineNum;boolinsect(Line&vline,Line&hline){ //pr......
  • POJ1737 Connected Graph ( n点无向连通图计数
    题意说明:求\(n\)个点的无向连通图个数据说已经非常典了,但是我太菜了不会组合数学,最近补档时看到这道题,决定记录下来理理思路......
  • POJ--1163 The Triangle(DP)
    记录10:432023-5-15http://poj.org/problem?id=1163reference:《挑战程序设计竞赛(第2版)》第二章练习题索引p135DescriptionFigure1showsanumbertriangle.Writeaprogramthatcalculatesthehighestsumofnumberspassedonaroutethatstartsatthetopa......
  • 实验六-Salt本地pojie实验
    【实验目的】了解Salt型密码的加密机制,学会使用本地密码pojie工具来pojieSalt型密码,了解pojie密码原理。【知识点】Salt,密码pojie【实验原理】1.Salt概念在密码保护技术中,salt是用来修改口令散列的随机数据串。可将salt加入散列,即使系统的另一用户也选用了同一口令,也可通过唯......
  • POJ 动态规划题目列表
    声明:1.这份列表当然不是我原创的,从文库里下载了一份,放到这里便于自己浏览和查找题目。※最近更新:Poj斜率优化题目1180,2018,3709列表一:经典题目题号:容易:1018, 1050, 1083, 1088, 1125, 1143, 1157, 1163, 1178, 1179, 1189, 1191,1208, 1276, 1322, 1414, 1456, 1458......