洛谷 P2022 有趣的数

题目描述

我们把一个数称为有趣的,当且仅当:

  1. 它的数字只包含0, 1, 2, 3,且这四个数字都出现过至少一次。

  2. 所有的0都出现在所有的1之前,而所有的2都出现在所有的3之前。

  3. 最高位数字不为0。

因此,符合我们定义的最小的有趣的数是2013。除此以外,4位的有趣的数还有两个:2031和2301。

请计算恰好有n位的有趣的数的个数。由于答案可能非常大,只需要输出答案除以1000000007的余数。

输入输出格式

输入格式:

输入只有一行,包括恰好一个正整数n (4 ≤ n ≤ 1000)。

输出格式:

输出只有一行,包括恰好n 位的整数中有趣的数的个数除以1000000007的余数。

输入输出样例

输入样例#1:
4
输出样例#1:
3
 1 有趣的数
 2 /*
 3 思路:
 4 字典序比k小的数分两种 
 5 1.比k小的数 
 6 2.比k大的数
 7 根据观察可以得出结论能算出比k小的字典序比k小的数的个数
 8 此时判断是否存在合法的
 9 分两种情况
10 1.1~k中比k字典序小的要超过要的m 不存在
11 2.若k为1 10 100 1000 100... 这样的数 那么前面只会有 数的位数-1个字典序小的数 
12 若m> 数的位数 不存在
13 除了这两种情况肯定能通过增加n补足m个字典序比k小的数 
14 */
15 #include<iostream>
16 #include<cstdio>
17 #include<cstring>
18 #define ll long long
19 using namespace std;
20 ll n,m,i,j,k,sum,l,p=1;
21 void init()
22 {
23     n=k;
24     while(n)
25     {
26         n=n/10;
27         l++;
28     }
29     sum+=(l-1);
30     for(i=1;i<=l-1;i++)
31      p=p*10;
32     n=k,i=p;
33     while(n)
34     {
35         sum+=(n-p);
36         n=n/10;
37         p=p/10;
38     }
39 } 
40 int main()
41 {
42     cin>>k>>m;
43     init();/*得到sum表示1~k中字典序比k小的的数的个数*/
44     if((k==i&&m-1>sum)||sum>=m)/*进行判断两种情况找不到*/
45     {
46         cout<<0<<endl;
47         return 0;
48     }
49     n=k,i=k-i;/*找比k大的字典序比k小的数的个数*/
50     while(sum<m-1)
51     {
52         i=i*10;
53         sum+=i;
54         n=n*10;
55     }
56     /*sum此时代表比n小的字典序比k小的数的个数*/
57     cout<<max(n-1-(sum-m+1),k)<<endl;
58     return 0;
59 }
原文地址:https://www.cnblogs.com/dingmenghao/p/5737964.html