码迷,mamicode.com
首页 > 编程语言 > 详细

C++ hdu 例题:不要62 题解

时间:2019-05-25 22:57:39      阅读:284      评论:0      收藏:0      [点我收藏+]

标签:c++   eve   接下来   ref   namespace   memset   +=   怎么   方法   

例题:不要62

同步数位DP

需要统计区间[l,r]的满足题意的数的个数,这往往可以转换成求[0,r]-[0,l)    

基本思想与方法

有了上述性质,我们就可以从高到低枚举第一次<n对应位是哪一位。

这样之前的位确定了,之后的位就不受n的限制即从00...0~99...9,可以先预处理,然后这时就可以直接统计答案。

预处理F数组。

F[i,st] 代表 位数为i(可能允许前导0。如00058也是个5位数),状态为st的方案数。这里st根据题目需要确定。

如i=4,f[i,st]也就是0000~9999的符合条件的数的个数(十进制)

决策第i位是多少(such as 0~9)

F[i,st] = F[i,st] + f[i–1,st‘]

st‘为相对应的状态

参照刚刚所说的基本思路。预处理f数组,然后统计[0,m] - [0,n).

f[i,j]代表开头是j的i位数中不含"62"或"4"的数有几个。

如f[2,6]包含60,61,63,65,66,67,68,69

for(i=1;i<=7;i++)//因为数据为1000000,所以预处理7位
for(j=0;j<=9;j++)//第i位
for(k=0;k<=9;k++)//第i-1位
if(j!=4&&!(j==6&&k==2))f[i][j]+=f[i-1][k];

接下来,怎么算出0-n和0-m区间的答案数呢?

用一个通用函数(Cal):

 如456=f[3][0]+f[3][1]+f[3][2]+f[3][3]+f[3][4](为什么不枚举到5呢?因为再下一位枚举了)

           +f[2][0]+f[2][1]+f[2][2]+f[2][3]+f[2][4](就是这一位)

           +f[1][0]+f[1][1]+f[1][2]+f[1][3]+f[1][4]+f[1][5]+f[1][6].

技术图片
#include<cstdio>//最右边是第一位
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
int f[10][10];
int Cal(int k)//求1~k中有多少符合的数.
{
    int len,digit[10],i,j,ans=0;
    memset(digit,0,sizeof(digit)),len=0;//digit[i]为当前的某个数从右到左第i个位置的数是多少.
    while(k>0){digit[++len]=k%10;k/=10;}
    for(i=len;i>=1;i--)
    {
        for(j=0;j<=digit[i]-1;j++)//每一位只能到k的下一位,所以计算的数实际只能到k-1.所以Cal()中传数要加1.
        {
            if(j!=4&&!(j==2&&digit[i+1]==6))ans+=f[i][j];
        }
        if(digit[i]==4||(digit[i]==2&&digit[i+1]==6))break; //如果这一位本来就没法,则后面的情况报废
    }
    return ans;
}
int main()
{
    int n,m,i,j,k;
    memset(f,0,sizeof(f));//f[i][j]为以j开始的且不含"62"和"4"位数为i的个数.
        f[0][0]=1;
        for(i=1;i<=7;i++)
        {
            for(j=0;j<=9;j++)//第i位
            {
                for(k=0;k<=9;k++)//第i-1位
                {
                    if(j!=4&&!(j==6&&k==2))f[i][j]+=f[i-1][k];
                }
            }
        }
    while(1)
    {
        scanf("%d %d",&n,&m);
        if(n==0&&m==0)break;
        printf("%d\n",Cal(m+1)-Cal(n));//因为当前的Cal(k)是计算出从1到k-1的符合条件的数的个数,所以要计算n~m的个数要用Cal(m+1)-Cal(n).
    }
    return 0;
}
View Code

 

C++ hdu 例题:不要62 题解

标签:c++   eve   接下来   ref   namespace   memset   +=   怎么   方法   

原文地址:https://www.cnblogs.com/mzyczly/p/10924285.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!