zoukankan      html  css  js  c++  java
  • 51nod1042

    给出一段区间a-b,统计这个区间内0-9出现的次数。
     
    比如 10-19,1出现11次(10,11,12,13,14,15,16,17,18,19,其中11包括2个1),其余数字各出现1次。
    Input
    两个数a,b(1 <= a <= b <= 10^18)

    Output
    输出共10行,分别是0-9出现的次数
    Input示例
    10 19
    Output示例
    1
    11
    1
    1
    1
    1
    1
    1
    1
    1
    思路:用记忆化搜索做,当计算0的数量是要特别注意
    代码
     
    #include<stdio.h>
    #include<string.h>
    #define ll long long
    ll dis[12];//记录位数 
    ll lg,len;
    ll s[25];//表示10的i次方 
    ll ans1[12];//记录答案 
    ll dp[25][15][2];
    ll check(ll a){ //计算分解后的前a位的值 
    	ll i=0;
    	ll ans=0;
    	for(i=0;i<=a;i++)
    	ans+=dis[i]*s[i];
    	return ans;
    }
    ll dfs(ll pos,ll lg,ll k){//计算1---9的数量 
    	if(pos<0)
    	return 0;
    	ll num=lg?dis[pos]:9;
    	if(!lg&&dp[pos][k][lg]!=-1)//只有没有限制的时候才能用记忆化记录的结果 
    	return dp[pos][k][lg];
    	ll i,j;
    	ll ans=0;
    	for(i=0;i<=num;i++){
    	if(i==k){//当i等于k时,当前有k的数量就要加上后面所有可能的数字的个数 (假设是542123,当前面已经遍历完542这三位时,
    	//当遍历到第四位且第四位为1时,1的数量就等于23中1数量+23)	 
    			if(lg&&i==num)//注意,前面的限制不一定能对后面的计算产生影响,要看当前的i是否可以继续产生限制。
    			ans=ans+check(pos-1)+1+dfs(pos-1,lg&&(i==num),k);//假设是542123这个数字,当取后三位是,一共有123+1种情况(0---123) 
    			else
    			ans=ans+s[pos]+dfs(pos-1,lg&&(i==num),k);// 假设是542123,当前面已经遍历到541这三位时,
    	//当遍历到第四位且第四位为1时,1的数量就等于100中1数量+100)	 
    		}
    		else
    		ans+=dfs(pos-1,lg&&(i==num),k);
    	}
    	if(!lg)
    	dp[pos][k][lg]=ans;
    	return ans;
    }
    ll dfs1(ll pos,ll lg,ll lg1){//计算零的数量 
    	if(pos<0)
    	return 0;
    	if(!lg&&!lg1&&dp[pos][0][lg]!=-1)//只有当没有限制并且前面有非零数字时,才能用到记忆化保存的数据 
    	{
    		return dp[pos][0][lg];
    	}
    	ll num=lg?dis[pos]:9;
    	ll i,j;
    	ll ans=0;
    	//printf("%d
    ",num);
    	//printf("pos=%d
    ",dis[pos]);
    	for(i=0;i<=num;i++){
    		//prllf("c=%d %d
    ",pos,i);
    		if(!lg1&&i==0){
    			if(lg&&i==num)//注意,前面的限制不一定能对后面的计算产生影响,要看当前的i是否可以继续产生限制,在这里连续卡了几次,以为自己考虑了,但是还是没有考虑,以后做题一定要注意。
    			{
    				//printf("a=%d %d %d
    ",pos,i,cal(pos)+1);
    				ans+=check(pos-1)+1;//同上 
    			}
    			else
    			{
    				ans+=s[pos];
    				//printf("b=%d
    ",s[pos]);
    			}
    			
    		}
    		//printf("%d %d %d
    ",pos,i,ans);
    		ans+=dfs1(pos-1,lg&&(i==num),lg1&&(i==0));
    		
    	 }
    	if(!lg&&!lg1)//记忆化没有限制并且前面有非零数字的情况 
    	dp[pos][0][lg]=ans;
    	return ans;
    }
    int main(){
    	ll n,m;
    	len=0;
    	scanf("%lld%lld",&n,&m);
    	ll i;
    	s[0]=1;
    	for(i=1;i<=18;i++)
    	s[i]=s[i-1]*10;
    	n=n-1;
    	while(n){//分解数字 
    		dis[len++]=n%10;
    		n=n/10;
    	}
    	memset(dp,-1,sizeof(dp));
    	ans1[0]=-dfs1(len-1,1,1);
    	//printf("%d
    ",ans1[0]);
    	for(i=1;i<=9;i++){	
    		ans1[i]=-dfs(len-1,1,i);
    	}
    	len=0;
    	while(m){
    		dis[len++]=m%10;
    		m=m/10;
    	}
    	ans1[0]+=dfs1(len-1,1,1);
    	printf("%lld
    ",ans1[0]);
    	for(i=1;i<=9;i++){	
    		ans1[i]+=dfs(len-1,1,i);
    		printf("%lld
    ",ans1[i]);
    	}
    	
    	return 0;
    }
    

      

    
    
  • 相关阅读:
    动态规划Dynamic Programming: Rod-Cutting Problem
    递归详解,全排列问题
    获取网站根目录Url
    oracle中操作表和权限
    mongo简单封装
    dapper的简单封装
    反射做字段更新日志
    nopcommerce +autofac +owin +webapi
    批处理命令执行程序
    MSMQ的简单使用
  • 原文地址:https://www.cnblogs.com/cglongge/p/9311906.html
Copyright © 2011-2022 走看看