参考:
http://blog.youkuaiyun.com/zhuhuangjian/article/details/23036139
http://blog.youkuaiyun.com/mid_kkks/article/details/23034401
本题预处理之后,就是一个背包问题,但是容量10e9,不能用背包。最后是判断出最多选择3个数,暴力解决或利用夹逼原理。
夹逼原理:2个数时,利用夹逼原理,O(n)解决。三个数时,枚举第一个,后两个夹逼原理判断。
//#pragma warning (disable: 4786)
//#pragma comment (linker, "/STACK:16777216")
//HEAD
#include <cstdio>
#include <ctime>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <string>
#include <set>
#include <stack>
#include <map>
#include <cmath>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int INF = 1000000007;
const double eps = 1e-10;
const int MAXN = 1000010;
int sn;
int sum[100000];
map<int, int>mp;
int n;
bool pd(int x)///夹逼原理判断2个数的和为x
{
int lowi = 1, upi = upper_bound(sum, sum + sn, x) - sum - 1;
while (lowi <= upi)
{
if (sum[lowi] + sum[upi] < x)
lowi++;
else if (sum[lowi] + sum[upi] > x)
upi--;
else
{
printf("%d %d", lowi, upi);
return true;
}
}
return false;
}
int main ()
{
mp.clear();
sn = 1;
mp[1] = 1;
sum[1] = 1;
while (1)
{
if (sum[sn] > 123456789) break;
sn++;
sum[sn] = sum[sn - 1] + sn;
mp[sum[sn]] = sn;
}
int t;
scanf("%d", &t);
while (t--)
{
scanf("%d", &n);
if (mp.count(n))
{
printf("%d\n", mp[n]);
continue;
}
if (pd(n))
{
puts(""); continue;
}
int upi = upper_bound(sum, sum + sn, n) - sum - 1;
for (int i = 1; i <= upi; i++)
{
if (pd(n - sum[i]))
{
printf(" %d\n", i); break;
}
}
}
return 0;
}
暴力处理:3个数时,枚举前两个,判断第三个。同时可利用3个数的大小关系优化。1个数直接判断,2个数时枚举一个,判断第二个。
//#pragma warning (disable: 4786)
//#pragma comment (linker, "/STACK:16777216")
//HEAD
#include <cstdio>
#include <ctime>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <string>
#include <set>
#include <stack>
#include <map>
#include <cmath>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int INF = 1000000007;
const double eps = 1e-10;
const int MAXN = 1000010;
int sn;
int sum[100000];
map<int, int>mp;
int n;
int main ()
{
mp.clear();
sn = 1;
mp[1] = 1;
sum[1] = 1;
while (1)
{
if (sum[sn] > 123456789) break;
sn++;
sum[sn] = sum[sn - 1] + sn;
mp[sum[sn]] = sn;
}
int t;
scanf("%d", &t);
while (t--)
{
scanf("%d", &n);
if (mp.count(n))
{
printf("%d\n", mp[n]);
continue;
}
int flg = 0;
int upi = upper_bound(sum, sum + sn, n) - sum;
for (int i = 1; i <= upi; i++)
{
if (mp.count(n - sum[i]))
{
printf("%d %d\n", i, mp[n - sum[i]]);
flg = 1;
break;
}
}
if (flg) continue;
flg = 1;
for (int i = upi; i >= 1 && flg; i--)
// for (int i = 1; i <= upi && flg; i++)
{
int x = n - sum[i];
int upj = upper_bound(sum, sum + sn, x) - sum;
for (int j = min(i, upj); j >= 1 && flg; j--)
// for (int j = 1; j <= upj && flg; j++)
{
int y = x - sum[j];
if (mp.count(y))
{
printf("%d %d %d\n", i, j, mp[y]);
flg = 0;
break;
}
}
}
}
return 0;
}