首页 > 其他 > 详细

单调数

时间:2014-04-14 02:59:08      阅读:507      评论:0      收藏:0      [点我收藏+]

问题 E: 单调数

时间限制: 1 Sec  内存限制: 128 MB
提交: 27  解决: 11
[提交][状态][讨论版]

题目描述

对于一个正整数x,如果x的每一位都不大于它右边一位上的数字,那么就称x是递增数,例如:112455718899111

类似的,如果x的每一位都不小于它右边一位上的数字,那么就称x是递减数,例如:986633177311111

递增数和递减数统称单调数。(111既是递增数,也是递减数,所以111肯定是单调数)

输入

有多组输入。

每组输入一个数n。(n<=100)

输出

对于每组输入数据中的n,输出小于10^n的单调数个数。

样例输入

6
10

样例输出

12951
277032


纠结了两个小时才做出来,被自己蠢哭了。。。

数位dp,想了好几种状态表示方案最后才成功,无语啊。。。

用dp[i][j]表示长度为i位,各位都不超过j时的单调数数量;

那么当i=1时,显然dp[i][j]=1 (j=1,2,...9)

当i=2时,以dp[2][3]为例,可能情况如下:

13,31,  23,32,  30, 33

共6种,下面分别讲解这六种情况:

13,31这两个数可以看作是分别在1这个数字前后添上3得到的,23,32同理;而03这种情况实际就是3,不符合,那么剩下30;而在3的前后添3都是33;

由以上可得规律:当i=2时,dp[2][j]=2+∑(dp[i-1][k]*2) (0<k<j)

而当i>2时,情况又有不同,以dp[3][3]为例:

通过之前的两步,已经可以得到得到i,j为(2,1),(2,2),(2,3)时的dp值,其具体情况如下:

(i,j) 可能情况 dp[i][j]
(2,1) 10,11 2
(2,2) 12,21,   20,   22 4
(2,3) 13,31,   23,32,   30,   33 6
现在要将长度i增加为3,可将数字3加入以上每种可能情况,得到如下:

  可能情况  
  310,311  
  123,321,   320,   322  
  133,331,   233,332,   330,   333  
可以看出该表与上表的一一对应关系,与由1推2时不同,只能将3单独加到前面或后面,这样我们目前便已经得到了满足(3,3)的12种情况,

但是!要注意,现在并没有找到所有情况,因为对于11,22这样的数,3仍可以随意加到其前后构成311,113,322,223,而33只能构成333.所以对于前j-1行,每行都要再多一种情况。

再检查一下是否所有可能情况已经找全了?

坑爹的我最后才发现竟然把300给忘了!

那么,当i>2时,最终得到的状态转移方程即为:dp[i][j]=∑(dp[i-1][k]+1) (1<=k<=j)

至此,规律已经找好了,接下来就是打表,计算

对于给定的n,要求的是小于10^n的单调数个数,即i可以等于1、2、3...n,j可以等于0、1、2...9;

那么,ans=dp[i][j] (i=1 to n)(j=0 to 9);


呼~解释完了,最后放一下AC代码:

(因为当时时间紧急,很多地方都写得很乱套,很多地方其实可以优化,不过总算是在比赛结束前两分钟的紧张时刻ac了,还是比较hp的,放上来仅作参考吧


#include<iostream>
#include<cstdio>
#include<cstring>

using namespace std;

long long dp[105][15];

int main()
{
	long long n;
	for(long long i=0;i<=9;++i)
	{
		dp[1][i]=1;
	}
	for(long long i=2;i<=2;++i)
	{
		dp[i][0]=0;
		for(long long j=1;j<=9;++j)
		{
			for(long long k=1;k<j;++k)
			{
				dp[i][j]+=(dp[i-1][k]*2);
			}
			dp[i][j]+=2;
		}
	}
	dp[1][0]=0;
	for(long long i=3;i<=100;++i)
	{
		dp[i][0]=0;
		for(long long j=1;j<=9;++j)
		{
			for(long long k=1;k<=j;++k)
			{
				dp[i][j]+=(dp[i-1][k]+1);
			}
			--dp[i][j];
			dp[i][j]+=1;
		}
	}
	while(cin>>n)
	{
		long long ans=0;
		for(int i=1;i<=n;++i)
		{
			for(long long j=0;j<=9;++j)
			{
				ans+=dp[i][j];
			}
		}
		cout<<ans<<endl;
	}
	return 0;
}

单调数,布布扣,bubuko.com

单调数

原文:http://blog.csdn.net/harrypoirot/article/details/23611567

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!