CodeForces - 960C_Subsequence Counting_二进制

题意

数列的所有子数列(不一定连续)中,删去最大元素和最小元素只差大于等于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;
}

猜你喜欢

转载自blog.csdn.net/Anna__1997/article/details/80033448
今日推荐