题意
数列的所有子数列(不一定连续)中,删去最大元素和最小元素只差大于等于d的子数列后,剩下x个,求一个这样的数列。
且数列长度不超过1e4,数列元素属于 1 ~ 1e18
思路
贪心构造数列,分为几组数,组内元素相同,相邻组相差d。
此时只有组内元素会产生符合要求的子数列,当第i组元素的个数位 ki 时,产生 2^ki - 1 个子数列。
要将 x 分解为 一系列
2^ki - 1 的和,不如先考虑分为
2^ki 的和,采用二进制位运算,多出来的单独分组即可。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define INF 0x3f3f3f3f
#define rep0(i, n) for (int i = 0; i < n; i++)
#define rep1(i, n) for (int i = 1; i <= n; i++)
#define rep_0(i, n) for (int i = n - 1; i >= 0; i--)
#define rep_1(i, n) for (int i = n; i > 0; i--)
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define mem(x, y) memset(x, y, sizeof(x))
#define MAXN 10010
using namespace std;
typedef long long ll;
ll x, d, a[MAXN];
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif // ONLINE_JUDGE
scanf("%lld %lld", &x, &d);
ll now = 1, tot = 0, cnt = 0; //cnt标记正在处理x的第几位
int tmp = 0; // 记录非零位个数
while (x)
{
if (now > 1e18 || tot > 10000)
{
printf("-1\n");
return 0;
}
if (x & 1)
{
tmp++;
for (int i = 0; i < cnt; i++)
{
a[tot++] = now;
}
if (cnt > 0)
now += d;
}
x >>= 1;
cnt++;
}
for (int i = 0; i < tmp; i++)
{
if (now > 1e18 || tot > 10000)
{
printf("-1\n");
return 0;
}
a[tot++] = now;
now += d;
}
printf("%d\n", tot);
printf("%lld", a[0]);
for (int i = 1; i < tot; i++)
printf(" %lld", a[i]);
printf("\n");
/*
if (x <= 10000)
{
printf("%d\n", x);
ll tmp = 1;
printf("1");
for (int i = 1; i < x; i++)
{
tmp += d;
printf(" %lld", tmp);
}
printf("\n");
}
else
{
ll tot = 1, p, now = 1, pre = 1;
a[1] = 1;
int i = 2;
while (tot < x)
{
if (i > 10000)
{
printf("-1\n");
return 0;
}
for (; i <= 10000; i++)
{
p = qpow(i - pre);
if (tot + p <= x)
{
tot += p;
a[i] = now;
if (a[i] > 1e18)
{
printf("-1\n");
return 0;
}
}
else
{
if (tot == x)
{
printf("%d\n", i - 1);
printf("1");
for (int t = 2; t < i; t++)
{
printf(" %lld", a[t]);
}
printf("\n");
return 0;
}
a[i] = now + d;
now += d;
pre = i;
//cout << tot << endl;
if (a[i] > 1e18)
{
printf("-1\n");
return 0;
}
tot++;
i++;
break;
}
}
}
printf("%d\n", i - 1);
printf("1");
for (int t = 2; t < i; t++)
{
printf(" %lld", a[t]);
}
printf("\n");
}
*/
return 0;
}