题目链接:
题目大意:
定义f(k,n)为类似菲波那契数推导,只不过变为前k项的和,然后给出一个数s,利用k-菲波那契数构造出一个不重复的集合的元素和为s,集合的规模大于1
题目分析:
- 首先因为菲波那契数的增长速度快的吓人,所以给的数据范围109很快就能达到,我们得到O(n)的构造出所有的可能用到的k-菲波那契数是可行的。
- 然后就是构造如何构造的问题了。
- 因为题目保证解一定存在,那么我们考虑如何构造一组可行解,采取的是贪心的方法,先选取能够选择的元素中最大的。
- 如果答案的集合只有1个元素,那么我们添上0保证得到的解的规模
-
f(k,n)−f(k,n−1)=f(k,n−1)−f(k,n−k−1)⇒f(k,n)−f(k,n−k−1)=2f(k,n−1)⇒f(k,n)≤2f(k,n−1)
这样如果对于给定数s的一个因数是数列中的数位置为n,倍数等于2,那么我们通过选取f(k,n+1)能够保证有合法解避免这种同一个数出现多次的冲突,找到最大的那个数,因为那个数不可能出现当前的s是它的两倍,因为s
AC代码:
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <set>
#include <vector>
#define MAX 100007
using namespace std;
typedef long long LL;
LL a[MAX];
int s,k,n;
multiset<int,greater<int> > col;
vector<int> ans;
int main ( )
{
while (~scanf ( "%d%d" , &s , &k ) )
{
col.clear();
ans.clear();
memset ( a , 0 , sizeof ( a ) );
n = 1;
a[1] = 1;
a[0] = 0;
while ( a[n]-a[n-1] <= s )
{
int l = max ( n-k , 0 );
a[n+1] = a[n]-a[l];
col.insert ( a[n+1] );
a[n+1] += a[n];
n++;
}
multiset<int>::iterator it;
/*cout << "------------------------------" << endl;
//multiset<int>::iterator it;
for ( it = col.begin() ; it != col.end() ; it++ )
cout << *it << endl;
cout << "---------------------------" << endl;*/
while ( s )
{
it = col.lower_bound ( s );
s -= *it;
ans.push_back ( *it );
col.erase ( it );
}
while ( k!= 1 && ans.size() < 2 ) ans.push_back ( 0 );
printf ( "%d\n" , (int)ans.size() );
for ( int i = 0 ; i < ans.size() ; i++ )
printf ( "%d " , ans[i] );
puts ("");
}
}