一步一步发现规律,优化代码,提炼公式
2025-05-28 12:51:06
发布于:安徽
7阅读
0回复
0点赞
#include<bits/stdc++.h>
using namespace std;
/*
找规律:
长m的边在第n层的三角形数为n-m+1
长m的顶点在第n层的三角形数等于边在第n-m层的三角形数
*/
// f1234都是有效的,不同形式而已
// 18ms
int f1(int N){
// 2n-3m+2 n表示第几层,m表示三角形单位长度
int sum = 0;
for(int n=1;n<=N;n++){
for(int m=1;m<=n;m++){
sum += (n-m+1) + max(n-m - m + 1, 0);
}
}
return sum;
}
// 动态规划 13ms
int a[501][501]; // a[n][m]表示边在第n层且长度为m的正三角形个数
int f2(int N){
int sum = 0;
for(int n=1;n<=N;n++){
for(int m=1;m<=n;m++){
a[n][m] = n-m+1;
// 长为m时,唯一顶点(倒三角)落在第n层的三角形数等于边落在第n-m层的三角形数
sum += a[n][m] + a[n-m][m];
}
}
return sum;
}
//11 ms
int f3(int N){
// 2n-3m+2 n表示第几层,m表示三角形单位长度
int sum = 0;
for(int n=1;n<=N;n++){
for(int m=1;m<=n;m++){
sum += (n-m+1);
// ((n-1+1)+(n-n+1))*n/2 = (n+1)*n/2
}
for(int m=1;m<=n/2;m++){
sum += n-m - m + 1;
// ((n-1-1+1)+(n-n/2-n/2+1))*(n/2)/2 = n*n/4
}
// 第n产生新三角形数为:(n+1)*n/2 + n*n/4
// = (3n*n+2n)/4
// f(n) = f(n-1)+(3n*n+2n)/4
}
return sum;
}
// 1ms (通过f3找到公式)
int f4(int n){
if(n==1) return 1;
return f4(n-1) + (3*n*n+2*n)/4;
}
int main(){
int t;
cin>>t;
while(t--){
int n;
cin>>n;
cout<<f4(n)<<endl;
}
}
在图中找规律,n等分将产生n层结构。将划分后的最短三角形边长记为1.
如图中,4等分后产生了4层结构。
在任意一层中,长度为1的三角形数可以分成两部分:
边落在第n层的正三角数 + 唯一顶点落在第n层的倒三角数。
而倒三角数可以视为来自上一层正三角的倒影。
再进一步观察三角形数:边落在第n层且长为m的正三角数为n-m+1
在第n层。长为m的倒三角形,它只能来自第n-m层的正三角形。
那么独属于第n层的长为m的三角形数为(n-m+1) + (n-m -m + 1) (后者公式中必须要求n-m>=m,不然结果为负)
那么依据这个思路,实现了函数f1, 有max函数来保证倒三角数不产生负的结果,耗时18ms左右。
进一步优化,将每层的结果用数组保存下来,避免重复计算,得到了f2函数,耗时13ms左右。
由于倒三角数存在的前提是n-m>=m,故m<=2/n,当m>2/n时不需要计算。为了将内循环划分为两部分分别计算,得到了f3函数,耗时降低到11ms.
最后,依据f3中内循环思路,将代码转换为数学公式,其实就是两个不同范围的数列和,化简过程见f3函数注释。最终,发现第n层独立产生的三角形数为(3n*n+2n)/4。由此也就产生了最后的递推形式代码f4函数。耗时1ms。
这样应该比较清晰展示了一步一步发现规律,总结规律,优化代码,提炼公式的过程。
最后,附上提交记录,从最开始的21ms到最后1ms。
大家写完代码最好尝试进一步优化代码,降低耗时,这能训练思维。
这里空空如也
有帮助,赞一个