没有想到什么好的算法……感觉很暴力的样子……
大致思路是先找一个刚刚好不越界的大正方形块,然后一根一根围墙往上加。
首先考虑方块数量与围墙之间的关系:
- 方块的数量是\(1^2\)
围墙的数量是\(2 \times 1 \times(1+1)\)
0 |
---|
- 方块的数量是\(2^2\)
围墙的数量是\(2 \times 2 \times(1+2)\)
0 | 0 |
---|---|
0 | 0 |
- 方块的数量为\(3^2\)
围墙的数量是\(2 \times 3 \times(1+3)\)
0 | 0 | 0 |
---|---|---|
0 | 0 | 0 |
0 | 0 | 0 |
对于\(n\)块的情况,围墙的数量是\(m=2n (1+n)\)
而现在给定的是围墙的数量\(m\),因此解方程\(m=2n (1+n)\)。
由求根公式:
\[ n=\lfloor \frac{ \sqrt{4+8m}-2}{4} \rfloor \]
算除了大正方形还剩下多少围墙:
\[
rest=m-2n(n+1)
\]
讨论剩下的围墙能围成几个块
\[
RestBlock=\left\{
\begin{aligned}
& \lfloor (rest-1)/2 \rfloor ,\quad \quad rest \leq 2n+1\\
& \lfloor (rest-1)/2 \rfloor +n, \ rest > 2n+1\\
\end{aligned}
\right.
\]
输出\(n^2+RestBlock\).
代码的变量跟题目不一样,请留意。
code:
#include<bits/stdc++.h> #define ll long long using namespace std; const int N=105,INF=0x3f3f3f3f; inline ll read() { char c=getchar();ll x=0; for(;!isdigit(c);c=getchar()); for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x; } void pr(ll x) { if(x/10)pr(x/10); putchar(x%10+'0'); } int main() { //for(int i=1;i<100;i++)cout<<i<<' '<<((int)(sqrt(4+8*i)-2)/4)<<endl; ll T=read(); while(T--) { ll n=read(); // cout<<T<<' '; //ll n=T; ll k= (sqrt(4+8*n)-2)/4; ll rest=n-2*k*(k+1); if(rest<=2*k+1) { ll dlt=(rest-1)/2; pr(dlt+k*k); putchar('\n'); } else { rest-=2*k+1; ll dlt= (rest-1)/2; pr(k*k+k+dlt); putchar('\n'); } } return 0; }