SP27267 VECTAR4 - Changus Final Battle

题意

试构造一个正整数数列 a1,a2,,ama_1,a_2,…,a_m,使得这个数列满足以下条件:

  • a1=am=1a_1=a_m=1

  • ai=ai11 or ai1 or ai1+1 a_i=a_{i-1}-1\ \text{or}\ a_{i-1}\ \text{or}\ a_{i-1}+1\ 2im2≤i≤m

  • i=1mai=n\sum_{i=1}^ma_i=n

求这个数列最短的长度。

最多有 10510^5 组数据,1n10181≤n≤10^{18}

分析

由于 nn 的范围超大,所以我们可以先打表找规律nn 较小的情况看。

nn 11 22 33 44 55 66 77 88 99
ansans 11 22 33 33 44 44 55 55 55

看起来很有规律:1,21,2 出现了 11 次,3,43,4 出现了 22 次,55 出现了 33 次,那 66 呢?

nn 1010 1111 1212 1313 1414 1515 1616 1717 1818 1919 2020
ansans 66 66 66 77 77 77 77 88 88 88 88

这时的规律就不言自明了,不过还是看不出正解……

于是我们把这个表转一下

ansans ansans 对应的 nn ansans 对应的 max(n)\max(n)
11 11 11
22 22 22
33 3,43,4 44
44 5,65,6 66
55 7,8,97,8,9 99
66 10,11,1210,11,12 1212
77 13,14,15,1613,14,15,16 1616
88 17,18,19,2017,18,19,20 2020

如果你还看不出来,那我只好打出来了:

  1=1×1  \ \ 1=1\times1\ \   2=1×2\ \ 2=1\times2

  4=2×2  \ \ 4=2\times2\ \   6=2×3\ \ 6=2\times3

  9=3×3  \ \ 9=3\times3\ \ 12=3×412=3\times4

16=4×4  16=4\times4\ \ 20=4×520=4\times5

ansans 对应的 max(n)=(ans+1) xor 12×((ans+1) xor 12+((ans+1) & 1))\max(n)=\left\lfloor\dfrac{(ans+1)\ \text{xor}\ 1}{2}\right\rfloor\times(\left\lfloor\dfrac{(ans+1)\ \text{xor}\ 1}{2}\right\rfloor+((ans+1)\ \&\ 1))

用人话来说,若 ansans 为偶数,则 max(n)=ans2×(ans2+1)=ans22+ans2\max(n)=\left\lfloor\dfrac{ans}{2}\right\rfloor\times(\left\lfloor\dfrac{ans}{2}\right\rfloor+1)=\left\lfloor\dfrac{ans}{2}\right\rfloor^2+\left\lfloor\dfrac{ans}{2}\right\rfloor;若 ansans 为奇数,则 max(n)=ans+122\max(n)=\left\lfloor\dfrac{ans+1}{2}\right\rfloor^2

又因为每个 ansans 对应的 nn 是连续的,所以我们可以根据 nn 所在的范围确定 ansans,记 a=na=\left\lfloor\sqrt{n}\right\rfloor,则:

n={2×a1n=a22×aa2<na×(a+1)2×a+1n>a×(a+1)n=\begin{cases}2\times a-1&n=a^2\\2\times a&a^2<n≤a\times(a+1)\\2\times a+1&n>a\times(a+1)\end{cases}

为什么是正确的呢?我们以 a=3a=3 来举例。

nn 99 1010 1111 1212 1313 1414 1515
aa 33 33 33 33 33 33 33
ansans 55 66 66 66 77 77 77

一一对照就能发现上面 nn 的求法是对的。

代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll t,n,a;
int main()
{
    cin>>t;
    while(t--)
    {
    	cin>>n;
    	a=sqrt(n);
    	if(n==a*a)
    		cout<<a*2-1<<endl;
    	else if(n<=a*(a+1))
    		cout<<a*2<<endl;
    	else
    		cout<<a*2+1<<endl;
	}
	return 0;
}
posted @ 2021-07-20 17:51  luckydrawbox  阅读(11)  评论(0)    收藏  举报  来源