Codeforces 1202D 思惟 構造

原題連接

ios

題意


  • 每組數據給咱們一個n,而後要求咱們用{1, 3, 7}這三種字符來組成一個長度小於1e5的序列,要求其中爲1337的子序列(不要求相鄰)的數量剛好爲n

思路


  • 首先能夠考慮最簡單的一種構造方式,開頭爲133,後面接n個7,這樣必定是正確的,可是長度會超過限定

    spa

  • 咱們注意到上面那種方法,每增長一個7,1337子序列數量會增長1,增長速度比較慢,因此咱們尋找一種新的「逼近n」的增加方法——也就是每增長一個7,1337的數量增長量爲一個變量

    code

  • 由於7前面是3,咱們考慮增長3的數量以後,再逐個增長7的數量

    get

  • 咱們發現,若是在增長的一個7前方有m個3,則1337子序列增長量爲string

\[m * (m - 1) / 2 \]


  • 這裏其實也就正好達到了咱們以前提到的目的,讓每次增長量爲變量,咱們能夠假設一開始1後面有無數的3,而後咱們從這些3中間插入7,每次插入的貢獻值顯然就是由上面的式子來算出。咱們設爲 \(f(m)\)

    it

  • 那麼如何使得咱們插入的k個7的貢獻值的和爲n?,也就是io

\[\sum_1^k{f(a_i)} = n \]

(a_i爲每次加入7時前方的3個數)

class

  • 咱們能夠對n 不斷減去小於等於它的最大f(m)(若是爲了容易思考,可使用二分逼近),同時記錄這個m,直到n等於0。這樣,咱們也就獲得了上面的a_i

    stream

  • 以後將a_i從小到大排列,不斷輸出補充3達到對應的a_i數量,而後結尾加上7,將全部a_i操做完以後,答案也就構造完畢了。

    變量

AC代碼

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

long long n;
int t;
long long aa[100005], co = 0;

long long search(long long x)
{
	long long l = 2, r = x * 2;
	while (l + 5 <= r)
	{
		long long mid = (l + r) >> 1;
		if ((mid - 1) * mid / 2 <= x)
		{
			l = mid;
		}
		else
		{
			r = mid - 1;
		}
	}
	while ((l - 1) * l / 2 <= x)
	{
		++l;
	}
	return l - 1;
}

int main()
{
	scanf("%d", &t);
	while (t--)
	{
		co = 0;
		scanf("%lld", &n);
		printf("1");
		while (n)
		{
			long long x = search(n);
			aa[++co] = x;
			n -= x * (x - 1) / 2;
		}
		int ll = 0;
		for (int i = co; i >= 1; --i)
		{
			while (ll < aa[i])
			{
				printf("3");
				++ll;
			}
			printf("7");
		}
		printf("\n");
	}
	return 0;
}
相關文章
相關標籤/搜索