Timus 1727. Znaika's Magic Numbers 要求将指定的正整数分解为一些不同的正整数的和。
1727. Znaika's Magic Numbers
Time Limit: 0.5 second
Memory Limit: 64 MB
Memory Limit: 64 MB
Znaika has many interests. For example, now he is investigating the properties of number sets. Znaika writes down some set consisting of different positive integers (he calls this set agenerating set), calculates the sum of all the written digits, and writes down the result in a special notebook. For example, for a generating set 7, 12, 43, he will write down the number17 = 7 + 1 + 2 + 4 + 3. Znaika is sure that only magic numbers can appear as a result of this operation.
Neznaika laughs at Znaika. He thinks that there is a generating set for every number, and he even made a bet with Znaika that he would be able to construct such a set.
Help Neznaika win the bet and construct a generating set for a given number.
Input
The only input line contains an integer n (0 < n < 105).
Output
If it is possible to construct a generating set for the number n, output the number of elements in this set in the first line. In the second line output a space-separated list of these elements. The elements of the set must be different positive integers strictly less than 105. If there are several generating sets, output any of them. If there are no generating sets, output −1.
Sample
input | output |
---|---|
17 |
3 7 12 43 |
Problem Author: Ivan Burmistrov
Problem Source: Ural Regional School Programming Contest 2009
Problem Source: Ural Regional School Programming Contest 2009
Tags: none
题意
这道题目要求将一个指定的正整数(小于105)分解为一些不同的正整数(也必须小于105)之和,这些正整数的各位数字和加起来刚好等于指定的正整数。
解答
使用 C# 语言解答如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | using System; // http://acm.timus.ru/problem.aspx?space=1&num=1727 static class Timus { static void Main() { int n = int .Parse(Console.ReadLine()); int count = Compute( ref n), tops = count; for ( int i = 0; n > 9; i++, n -= 10) count++; int tens = count - tops; Console.WriteLine(count += ((n > 0) ? 1 : 0)); for ( int i = 99999; tops-- > 0; i--) Console.Write(i + " " ); while (tens-- > 0) Console.Write( "19 28 37 46 " .Substring(tens * 3, 3)); if (n > 0) Console.Write(n); } static int Compute( ref int n) { int count = 0; for ( int sum = 45; n >= 45; ) { n -= sum--; if (++count % 10 == 0) sum += 9; if (count % 100 == 0) sum += 9; if (count % 1000 == 0) sum += 9; } return count; } } |
分析如下:
- 首先从 99999 开始往下倒数,直到 n 小于 45。注意,99999 的各位数字之和刚好等于 45,这也是最大的各位数字之和了。
- 然后利用 19、28、37、46 这四个各位数字之和刚好为 10 的数字。
- 最后 n 必然小于 10,如果 n 不为零的话,直接输出 n。
- Compute 方法就是执行从 99999 开始往下倒数的过程。其各位数字和是很有规律的,也就是从 45 开始往下递减,每遇到整十、整百、整千再加 9。
此外,还可以使用随机算法,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | using System; using System.Linq; using System.Collections.Generic; // http://acm.timus.ru/problem.aspx?space=1&num=1727 static class Timus { static void Main() { var n = int .Parse(Console.ReadLine()); var set = Compute( ref n); var count = set .Count; for ( var i = 0; n > 9; i++, n -= 10) count++; var tens = count - set .Count; Console.WriteLine(count += ((n > 0) ? 1 : 0)); foreach ( var i in set ) Console.Write(i + " " ); while (tens-- > 0) Console.Write( "19 28 37 46 " .Substring(tens * 3, 3)); if (n > 0) Console.Write(n); Console.WriteLine(); } static HashSet< int > Compute( ref int n) { var set = new HashSet< int >(); for ( var rand = new Random(); n >= 45; ) { var k = rand.Next(100, 100000); if ( set .Add(k)) n -= k.ToString().Select(x => x - '0' ).Sum(); } return set ; } } |
这个程序使用 HashSet 保存随机生成的正整数,以便丢弃重复的正整数,以及稍后输出这些正整数。注意第 28 行使用 Select 及 Sum 扩展方法进行各位数字求和。
第一个程序运行时间是 0.14 秒,第二个程序也不慢,运行时间是 0.156 秒。
让我们进行一下测试吧:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | using System; using System.Linq; using System.Diagnostics; static class Tester { static void Main( string [] args) { var n = (args.Length == 0) ? 100000000 : int .Parse(args[0]); Run(n, DigitsSum1); Run(n, DigitsSum2); } static void Run( int n, Func< int , int > func) { var timer = Stopwatch.StartNew(); long sum = 0; for ( var i = 0; i <= n; i++) sum += func(i); timer.Stop(); Console.WriteLine( "{0} {1:N0} {2:N0}" , timer.Elapsed, n, sum); } static int DigitsSum1( this int n) { var sum = 0; for (; n > 0; n /= 10) sum += n % 10; return sum; } static int DigitsSum2( this int n) { return n.ToString().Select(x => x - '0' ).Sum(); } } |
这个程序的运行结果如下所示:
E:\work>tester 00:00:20.3631972 100,000,000 3,600,000,001 00:00:58.6052102 100,000,000 3,600,000,001
看来使用 Linq 进行求和也不会很慢。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· [AI/GPT/综述] AI Agent的设计模式综述