洛谷 P2022 有趣的数
题目描述
我们把一个数称为有趣的,当且仅当:
-
它的数字只包含0, 1, 2, 3,且这四个数字都出现过至少一次。
-
所有的0都出现在所有的1之前,而所有的2都出现在所有的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 }