题解:P10373 [AHOI2024 初中组] 立方根

woscxk

2024-04-22 11:08:27

Solution

# 本蒟蒻的第一篇 tj,如果有问题请各位 dalao 们指出 **Upd On 2024/4/22 16:14 : 因为被 hack 了,我更新了 1 种 $O(t)$ 的数学方法。** **Upd On 2024/4/28 19:42: 打回后更改了 latex。** ## #1: 暴力! 一看到这题目,首先想到的肯定是暴力,直接去套公式。 ```cpp #include<bits/stdc++.h> using namespace std; int main(){ int t; cin>>t; long long output[t]; for(int i=0;i<t;i++){ long long x,sum=0; cin>>x; for(int j=1;j<=x;j++){ sum+=floor(cbrt(j)); } output[i]=sum; } for(int i=0;i<t;i++){ cout<<output[i]<<'\n'; } } ``` 然后你就~~成功的~~ TLE 了 (20pts) $O(xt)$ 的复杂度,$2 \times 10^5 \times 10^{12}=2 \times 10^{17}$ , 严重 TLE。 暴力过不了,我们就得引入另一种方法了。 他就是人见人爱,花见花开,车见车爆胎的 ## #2:~~打表!~~ 我们可以在程序内部打表,打出每个 $j^{1/3}$ 向下取整的个数 例如样例中提到的 $[\text{1,1,1,1,1,1,1,2,2,2}]$ 我们可以理解为 $7$ 个 $1$,$3$ 个 $2$,对应的就是 $[0,7,3]$ 在索引为 $x$ 时值为 $y$,就代表有 $y$ 个 $x$ 由此,代码也就呼之欲出了 ```cpp #include<bits/stdc++.h> using namespace std; long long a[10001];//表 int main(){ for(int i=0;i<10001;i++){//打表程序 a[i]=pow(i+1,3)-pow(i,3); } int t; cin>>t;//q long long output[t]={};//集体输出数组 for(int i=0;i<t;i++){ long long x,sum=0; scanf("%lld",&x); for(int j=1;x>0;j++){ if(x>=a[j]){ x-=a[j]; sum+=a[j]*j; }else{//如果只占一部分,将x消耗完并令x=0 sum+=x*j; x=0; } } output[i]=sum; } for(int i=0;i<t;i++){ printf("%lld\n",output[i]); } } ``` 复杂度 O ($tx^{1/3}$) ,$2 \times 10^5 \times 10^4=2 \times 10^9$, 无伤通过 subtask #0. ## #3: 数学 感谢 @Breath\_of\_the\_Wild 的 [tj](https://www.luogu.com/article/2ofym2gn) 的指导! 注:$[x]$ 表示 $x$ 向下取整 如 #2 所言,$a_{n}=(i+1)^3-i^3$ 而当 $$ x_{i} \ge \sum_{i=1}^{n-1}{x_i} $$ 时,sum 就加上了这一“整块” 的得分。即 $i((i+1)^3-i^3)$ 化简得:$3i^3+3i^2+i$ 那么对于整块 1 + 整块 2+…+ 整块 $[n^{1/3}]-1$ 答案为: $$ \sum_{i=1}^{[n^{1/3}]-1}{(3i^3+3i^2+i)} $$ 设 $[n^{1/3}]=t$。 则化简得:$\frac{3}{4}t^2(t-1)^2+\frac{1}{2}t(t-1)(2t-1)+\frac{1}{2}t(t-1)$。 除了整块的部分,还有零碎的部分: 从 $j=t^3$ 开始,$[j^{1/3}]=t$ 了,到 $n$ 就是 $n-t^3+1$,乘上权重就是 $t(n-t^3+1)$ 合起来太麻烦了~~自己算去吧!~~,我们可以将他们分存到两个变量中,但是直接相加是没有任何问题的。 ## #4: 上代码! 20 分: ```cpp #include<bits/stdc++.h> using namespace std; int main(){ int t; cin>>t; long long output[t]; for(int i=0;i<t;i++){ long long x,sum=0; cin>>x; for(int j=1;j<=x;j++){ sum+=floor(cbrt(j)); } output[i]=sum; } for(int i=0;i<t;i++){ cout<<output[i]<<'\n'; } } ``` 100 分 unac: ```cpp #include<bits/stdc++.h> using namespace std; long long a[10001];//表 int main(){ for(int i=0;i<10001;i++){//打表程序 a[i]=pow(i+1,3)-pow(i,3); } int t; cin>>t;//q long long output[t]={};//集体输出数组 for(int i=0;i<t;i++){ long long x,sum=0; scanf("%lld",&x); for(int j=1;x>0;j++){ if(x>=a[j]){ x-=a[j]; sum+=a[j]*j; }else{//如果只占一部分,将x消耗完并令x=0 sum+=x*j; x=0; } } output[i]=sum; } for(int i=0;i<t;i++){ printf("%lld\n",output[i]); } } ``` ac: ```cpp #include<bits/stdc++.h> using namespace std; typedef long long ll; ll T,n; int main(){ cin>>T; while(T--){ cin>>n; ll l=pow(n,1.0/3); if(l*l*l<n&&(l+1)*(l+1)*(l+1)<=n) l++; else if(l*l*l>n) l--;//调整精度 cout<<(l-1)*(l-1)*l*l*3/4+(l-1)*l*(2*l-1)/2+l*(l-1)/2+(n-l*l*l+1)*l<<'\n'; } return 0; } ``` 温馨小提示: ### ~~不开 long long 见祖宗~~ ###### (小声 bb):~~再次~~望管理大大过审!