首先学习一下lower_bound()
函数lower_bound()在first和last中的前闭后开区间进行二分查找,返回大于或等于val的第一个元素位置。如果所有元素都小于val,则返回last的位置
举例如下:
一个数组number序列为:4,10,11,30,69,70,96,100.设要插入数字3,9,111.pos为要插入的位置的下标
则
pos = lower_bound( number, number + 8, 3) - number,pos = 0.即number数组的下标为0的位置。
pos = lower_bound( number, number + 8, 9) - number, pos = 1,即number数组的下标为1的位置(即10所在的位置)。
pos = lower_bound( number, number + 8, 111) - number, pos = 8,即number数组的下标为8的位置(但下标上限为7,所以返回最后一个元素的下一个元素)。
所以,要记住:函数lower_bound()在first和last中的前闭后开区间进行二分查找,返回大于或等于val的第一个元素位置。如果所有元素都小于val,则返回last的位置,且last的位置是越界的!!~
返回查找元素的第一个可安插位置,也就是“元素值>=查找值”的第一个元素的位置
参考http://blog.csdn.net/niushuai666/article/details/6734403
http://blog.csdn.net/ck_boss/article/details/23040385
解题思路:
看网上题解说至多会有3个可以拆分的因素...应该是可以证明的吧 = =
思路就是,先判断n是否可以由一个因素构成
然后就是判断n是否可以有两个因素构成
这里有点小技巧:
1 int t2 = lower_bound( p , p + i + 1 , n - p[i] ) - p;//t2为另外一上限 2 for(int j = t2 ; j && p[i] + p[j] * 2 >= n ; j-- )
t2即为第二个因素的上限
然后查找第三个元素的时候,就简单了
只需要判断是否恰好满足条件即可
if(p[i]+p[j]<n){ int temp=n-p[i]-p[j]; t=lower_bound(p,p+16000,temp)-p; if(p[t]==temp){ flag3=true; c=i,d=j,e=t; }
完整AC代码:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 int p[16000]; 7 void init(){ 8 int sum=0; 9 for(int i=1;i<16000;i++){ 10 sum += i; 11 p[i]=sum; 12 } 13 } 14 int main(){ 15 int numCase,n; 16 scanf("%d",&numCase); 17 init(); 18 while(numCase--){ 19 scanf("%d",&n); 20 int t = lower_bound(p,p+16000,n)-p;//t为n在p数组中下标上限 21 //printf("t = %d\n",t); 22 if(p[t] == n){ 23 printf("%d\n",t); 24 continue; 25 } 26 bool flag2=false,flag3=false; 27 int a,b,c,d,e; 28 for(int i = t ; i && p[i] * 2 >= n ; i--){//p[i] * 2 >= n为下限 29 if(flag2) break; 30 int t2 = lower_bound(p,p+i+1,n-p[i]) - p;//t2为另外一上限 31 for(int j=t2;j&&p[i]+p[j]*2>=n;j--){ 32 if(flag2) 33 break; 34 if(p[i]+p[j]==n){ 35 flag2=true; 36 a=i,b=j; 37 break; 38 } 39 else if(flag3) 40 continue; 41 else if(p[i]+p[j]<n){ 42 int temp=n-p[i]-p[j]; 43 t=lower_bound(p,p+16000,temp)-p; 44 if(p[t]==temp){ 45 flag3=true; 46 c=i,d=j,e=t; 47 } 48 } 49 } 50 } 51 52 if(flag2) 53 printf("%d %d\n",a,b); 54 else 55 printf("%d %d %d\n",c,d,e); 56 } 57 return 0; 58 }
Pierre is recently obsessed with an online game. To encourage users to log in, this game will give users a continuous login reward. The mechanism of continuous login reward is as follows: If you have not logged in on a certain day, the reward of that day is 0, otherwise the reward is the previous day's plus 1.
On the other hand, Pierre is very fond of the number N. He wants to get exactly N points reward with the least possible interruption of continuous login.
There are multiple test cases. The first line of input is an integer T indicates the number of test cases. For each test case:
There is one integer N (1 <= N <= 123456789).
For each test case, output the days of continuous login, separated by a space.
This problem is special judged so any correct answer will be accepted.
4 20 19 6 9
4 4 3 4 2 3 2 3
20 = (1 + 2 + 3 + 4) + (1 + 2 + 3 + 4)
19 = (1 + 2 + 3) + (1 + 2 + 3 + 4) + (1 + 2)
6 = (1 + 2 + 3)
9 = (1 + 2) + (1 + 2 + 3)
Some problem has a simple, fast and correct solution.