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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章