Sequence
Time Limit: 2000/2000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 891 Accepted Submission(s): 271
Problem Description
Today, Soda has learned a sequence whose
n-th(n≥1)
item is 3n(n?1)+1.
Now he wants to know if an integer m
can be represented as the sum of some items of that sequence. If possible, what are the minimum items needed?
For example, 22=19+1+1+1=7+7+7+1.
Input
There are multiple test cases. The first line of input contains an integerT(1≤T≤104),
indicating the number of test cases. For each test case:
There‘s a line containing an integer m(1≤m≤109).
Output
For each test case, output
?1
if m
cannot be represented as the sum of some items of that sequence, otherwise output the minimum items needed.
Sample Input
10 1 2 3 4 5 6 7 8 22 10
Sample Output
1 2 3 4 5 6 1 2 4 4
题意,给出一个数列3n(n?1)+1,再给一个任意一个数m,要求最少能用多少个数列中的数之和为m
给出一个规律:n*(n-1)/2是三角形数,任何一个自然数可用最多三个三角形数拼成,这个规律得知道,才可以解出这题。
把上式变形得到6*(n * (n-1)/2) + 1;如果,m是由k个数组成,那m不就可以表示成6 * (k个三角形数之和) + k这样的形式了。k个三角形数之和,如果k>
=3,那么,由上面的规律,我们可以马上知道,这样的数肯定是存在的。k = 1 k = 2,要分开讨论。k = 1时,只需要二分找出是数列中的一个数就可以了。
k = 2时,找出 pri[i] + pri[j] = m(pri是给出的数列),这样的i,j是否存在, 一种方法,枚举i,得到m - pri[i] 判定是否在pri中,这样的复杂度是o(n * log(n)),
n是这个数列的个数。显然复杂度太高,我们知道,pri这个数列是递增的,我们可以用这个性质,i = 0 ,j = prilen -1;如果pri[i] + pri[j] > m;j--;否则i++;这
样,一定可以找出来是否和为m且复杂度只能o(n),这样才能过这题。由于i 只会加n次,j也只会减n次,所以总的复杂度为o(N)
为什么这样是对的呢,其实很简单,假设pri[ii] + pri[jj] = m,这样的方法,会不会,没找到ii,jj呢,不会,
初始 i < ii j>jj;如果pri[i] + pri[j] < m i++,否则j--,
1.假如,i先到达ii,此时,j > jj,pri[i] + pri[j] > pri[ii] + pri[jj] = m ;所以j--,最终一定会是,j = jj;
2.假如,j先到达jj,此时,i < ii,pri[i] + pri[j] < pri[ii] + pri[jj] = m ;所以i++,最终一定会是,i = ii;
所以不管怎么样,一定会找到答案。
#define N 205 #define M 100005 #define maxn 205 #define MOD 1000000000 int n,glen,len,pn,m,pri[M]; set<int> myset; set<int>::iterator it; bool solve1(int mm){ return myset.count(mm); } bool solve2(int mm){ for(int i = 0,j = pn -1;i< pn && pri[i] <= mm;i++){ while(j>= 0 && pri[i] + pri[j] > mm)j--; if(j>=0 && pri[i] + pri[j] == mm) return true; } return false; } int main() { pn = 0; for(int i = 1;i< M -1 ;i++){ int t = 3 * i * (i-1) + 1; if(t <= MOD){ pri[pn++] = t; myset.insert(t); } else break; } while(S(n)!=EOF) { while(n--){ S(m); if(m%6 == 1){ if(solve1(m)) printf("1\n"); else printf("7\n"); continue; } else if(m%6 == 2) { if(solve2(m)) printf("2\n"); else printf("8\n"); continue; } else printf("%d\n",(m - 1)%6 + 1); } } return 0; }
Source
Recommend
hujie | We have carefully selected several similar problems for you: 5315 5314 5310 5309 5308
版权声明:本文为博主原创文章,未经博主允许不得转载。