题意:
给定一个n,m。要求构造一个单调递增的序列,要求a[i]+a[j]=a[k]的数量恰好等于m
分析:
首先思考如何构造得到的满足条件的三元对尽可能多,那就是从1,2,3…n这样构造,那么对于每个加进来的数,对答案的贡献就是当前存在的数除以2。那么当贡献超过m时,就可以将下标往右移,这个数为a[index]+a.back(),对答案的贡献就是剩余元素个数除以2。
对于已经n个元素,但贡献小于m时,就是无解。若已经到达了m,那么我们如何构造剩下的元素呢?
这时我们就从可取的最大值出发,以每次减少原来的最大值+1的速度减少,因为n较小,且前面的数都是连续的,所以新的这些数根本不会小于最大值的一半。这样就能保证剩下的数不会对答案产生贡献。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
vector<int> ans;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n,m;
cin >> n >> m;
if( n == 1 )
{
if( m == 0 ) cout << 1 << '\n';
else cout << -1 << '\n';
return 0;
}
ans.push_back(1);
ans.push_back(2);
while( m )
{
if( ans.size() == n ) break;
int t = ans.size() / 2;
if( m > t )
{
m -= t;
ans.push_back(ans[0]+ans.back());
}else
{
int index = 0;
while( m != t )
{
index ++;
t = ( ans.size() - index ) / 2;
}
m = 0;
ans.push_back(ans[index]+ans.back());
}
}
if( m ) cout << -1 << '\n';
else
{
int t = ans.back() + 1;
int begin = 1e9;
while( ans.size() != n )
{
begin -= t;
ans.push_back(begin);
}
sort(ans.begin(),ans.end());
for (int i = 0; i < ans.size(); i++)
{
cout << ans[i];
if( i == ans.size() - 1 ) cout << '\n';
else cout << ' ';
}
}
return 0;
}