1.题意描述
给定边长为1,2,3,····n的n条边,现在要在里面任意选取三条边构成三角形,我们需要求一共可以构成多少个三角形?
2.题目分析
首先我们分析数据大小问题,由于数据最大可以达到10^6。所以我们如果直接枚举时间复杂度可以达到O(n^3),那么我们可以肯定的说这个时间复杂度肯定是不能承受的。
那么我们可以根据前面求整理的排列组合公式的求二项式系数的方法联想到使用递推法。这样时间复杂度可以降低到O(n)。这是可以承受的。要想用递推法,我们肯定需要使用打表的方法----预处理,那么空间复杂度肯定是O(n)同样可以承受。现在我们分析怎样使用递推法:
我们先定义一个函数f(n):当最大编程为n时所能构成的三角形数目。
对于三角形的三边而言,我们可以设定为x,y,z。并且我们假设x是最大边。那么我们有y+z>x,因此可以推出x-y<z<x。
根据这个不等式我们有,当y=1时,显然无解;当y=2时,有一个解;当y=3时,有两个解;·····当y=x-1时有x-2个解。根据等差数列求和公式我们有一共有
0+1+2+······+(x-2)=(x-1)(x-2)/2。但是我们需要注意,这里包含了y=z情况。那么我们需要减去从y=x/2+1开始到y=x-1为止,此时我们多计数了(x-1)-(x/2+1)+1=(x-1)/2个解,而且除此之外,我们对于每一个y我们都有重复计数,因为前后是对称的。所以我们最后还要除以2得到最终结果。
最终结果为:
那么最后的递推式我们可以写为:
到这里基本分析完毕。
wa的第一点 数组超了,后面还存了10000005
wa的第二点 数据爆了,不要强制转换,直接定义i为longlong
1 #include2 #include 3 #include 4 using namespace std; 5 long long f[1000001];//wa的第一点 数组超了,后面还存了10000005 6 int main() 7 { 8 //先打表预处理 9 f[3]=0;10 for(int i=4;i<=1000005;i++)11 f[i]=f[i-1]+(long long)(((i-1)*(i-2)/2-(i-1)/2)/2);// wa的第二点 数据爆了,不要强制转换,直接定义i为longlong 12 int n;13 while(~scanf("%d",&n))14 {15 if(n<3)16 break;17 cout< <
ac代码:
#include#include #include using namespace std;long long f[1000010];int main(){ //先预处理 f[3]=0; for(long long i=4;i<=1000005;i++) f[i]=f[i-1]+((i-1)*(i-2)/2-(i-1)/2)/2; int n; while(~scanf("%d",&n)) { if(n<3) break; cout< <