[数位DP][组合数学][整数分段] UVa 11038 How Many O’s?

自己写了个有点繁杂的数位dp,本来一发过还有点高兴,但是看了前排dalao代码发现自己写的太复杂了。。。。这个题其实只用组合数学就可以解emmmm

先上自己的屌丝做法:分段dp,从前往后,组合数学算下可以知道能预处理出来一段长度为n的可以包含前导0的数据的所有0的个数,我本来想的是用f(p,m,isf)表示当前是第p个数字,最大为m然后是否为上限isf表示状态,但是写着写着发现不用这么来。。。。所以其实到最后程序里的isf就没有用(在发现这一点的时候我就该想到其实不用这么“dp“),把当前位为0特判一下加上后面的所有可能数字(这个也可以预处理),算完当前这一位之后往下一位继续算。。。最后由于我在f里面的枚举都是从0开始,所以等于说算出来的是”可以包含前导0的数的0的个数“,所以在cal里面还要减去所有的前导0的个数。。。麻烦一批

再说dalao们的做法:其实这个前导0的问题很容易解决。。。从后往前算就ok了,每次算到一位的时候判断是不是0,不是0的话,可以想到当前位为0的话总共出现的次数是容易计算的:把整个数字从这个点分开成左右两段(不包括当前这一位),那么左边的数字*10^(右边的位数),如果当前为0那就不能这么算了(跟数位dp一个道理,isf的时候不能当成所有的情况来做),但是仍然很简单:只要左边不是最大的那个数字,右边仍然可以取到所以情况,所以这时候把左边-1乘上右边的10幂,再加上右边所有的本身的上限就行了。。。还是看代码比较好说。

继续阅读“[数位DP][组合数学][整数分段] UVa 11038 How Many O’s?”