这道题是今天晚上在c++交流群和一位水友给出的问题,有些同学试着解答了下;问题阐述如下:
题目文字略去,看图即可。
其中@jevon 的解答如下:
也没有帮他验证;但是基本思路就是:
遍历每一天,用一个 index 值来记录当天的索引,当出现次数 cout 达到索引值时,索引值++;
我于是帮他用java写一个就是这个意思;我的vs出问题了,所以用的java;
public class Demo33 { public static void main(String[] args) { for(int i=1;i<=20;i++){ setMC(i); } } public static int setMC(int day){ int sum = 1; int cout = 1; int index = 1; String s = "1"; for(int i=1;i<day;i++){ if(cout < index-1){ cout++; }else{ cout = 0; index++; } sum += index; if(i != day-1){ s = s + "+" + index; }else{ s = s + "+" +index + "=" + sum ; } } System.out.println(s); return sum; } }但是经过我的思考,一道程序题不是为了考察编写程序而单一的出现,所以一定是有优化的方法。
所以经过我的思考,发现索引值满足;索引值为a;
等差数列求和 a(a-1)/2 <= day < a(a+1)/2;所以可以计算出完整的a;同时得到剩下的p个(a+1)项
例如 1+2+2+3+3+3+4+4;这里面a = 3;p = 2;凑成完全的1+2^2+3^2+3^2;的索引正好是3;余下两个p (index) = a+1的残项;
而输入的结果 result = 1^2 + 2^2 + ... a^2 + (a+1) * p = a(a+1)(2a+1)/6 + p(a+1);
所以编写程序如下:
import java.util.Scanner; public class Demo { public static void main(String[] args) { int day = new Scanner(System.in).nextInt(); int a = setCout_n(day);//a就是能凑成完整的1+2^2+3^2+...+a^2 + (a+1)*p; int p = day - (int)(a*(a+1)/2); int result = (a*(a+1)*(2*a+1)/6) + (a+1)*p; System.out.println(result); } public static int setCout_n(int day){ int n = (int)(Math.sqrt(2*day + 0.5)+0.25); while(day < (int)((n*n - n)/2 + 0.5)){ n++; } return n-1; } }要是为了看到完整的验算过程;补充一个printRR函数,方便观看1-100完整的生成过程。
下面是验算的代码块,和上面的函数相同,只是加了一些控制台输出。
public class Demo { public static void main(String[] args) { for (int i=0;i<100;i++){ demo(i); } } public static void demo(int day) { int a = setCout_n(day);//a就是能凑成完整的1+2^2+3^2+...+a^2 + (a+1)*p; System.out.println("输入天数" + day); int p = day - (int)(a*(a+1)/2); System.out.println("完全数a = "+ a +", 余下来的p项,p = "+p); int result = (a*(a+1)*(2*a+1)/6) + (a+1)*p; System.out.println(result); printRR(a, p); } public static int setCout_n(int day){ int n = (int)(Math.sqrt(2*day + 0.5) + 0.25); while(day < (int)((n*n - n)/2 + 0.5)){ n++; } return n-1; } public static void printRR(int a,int p){ String s ="["; int sum = 0; for(int i=1;i<=a;i++){ s = s+ "("; for (int j=0;j<i;j++){ if(j==0){ s = s + i;sum+=i; }else{ s = s + "+" + i;sum+=i; } } if(i==a){ s = s+")"; }else{ s =s + ")+";} } if(p>0){ s = s +"+("; for (int j = 0; j< p;j++){ if(j==0){ s = s + (a+1); sum+=(a+1); }else{ s = s + "+" + (a+1); sum+=(a+1); } } s = s+")"; } s = s + "] = "+ sum; System.out.println(s); } }结论:这个题要是用数学知识直接解答复杂度大大降低,忽略系统运算中sqrt的复杂度;我们可以得到我的方法时间复杂度大约是O(lg(n));而他的方法是O(n).