【题解-SP1724 TRICOUNT】简单易懂的递推式写法

原题:
给你一个数N,下面是N行数据,每行一个数level,表示三角形的层数,对于每一个level,你需要输出其中三角形的个数。

样例输入:

3

1

2

3

样例输出:

1

5

13

数据范围:0<N<1000000,0<level<1000000。

这道题其实用通项公式就可以A了,挺简单的...~~(奈何本蒟蒻不会)~~
于是经过一番捣鼓,我还是得到了一个解法。(就类似于递推公式)
关于通项公式的解法,非常简单:

当level为偶数时,三角形个数为 level*(level+2)*(2*level+1)/8;

当level为奇数时,三角形个数为 (level+1)*(2*level*level+3*level-1)/8。

于是代码如下:

 1 #include<bits/stdc++.h>
 2 #define ull unsigned long long
 3 using namespace std;
 4 ull n,level;
 5 int main() 
 6 {
 7     cin>>n;
 8     for(ull i=1;i<=n;i++)
 9     {
10         cin>>level;
11         if(level%2)cout<<(level+1)*(2*level*level+3*level-1)/8<<endl;
12         else cout<<level*(level+2)*(2*level+1)/8<<endl;
13     }
14 }

但我不知道这个通项公式,也没那么多时间证,怎么办呢?

对于level n而言,每增加至level n+1,那么新的三角形中包含的总三角形个数就等于:

level n时总三角形个数 + level n+1时又新增的三角形个数。

于是,我们只需要求出每增加一层后又新增的三角形数就完事了。

(~~不过这个东西数起来好像有点脑阔疼。~~)

我们可以分别数出新增加的正立三角形和倒立三角形的个数,这样子就比较好数,再把它们相加就可以了。

撒,开始作业吧。

------------


对于正三角形:
level=1, 新增了边长为1的三角形1个。

level=2,新增了边长为1的三角形2个,边长为2的三角形1个。

level=3,新增了边长为1的三角形3个,边长为2的三角形2个,边长为3的三角形1个。

level=4,新增了边长为1的三角形4个,边长为2的三角形3个,边长为3的三角形2个,边长为4的三角形1个。
……

不难发现,设pz[i]为在增加至第i层时,较第i-1层应该新增的正三角形数的话,则pz[i]=pz[i-1]+i。

再设z[i]为增加至第i层时总共的正三角形数,那么z[i]=z[i-1]+pz[i]。

对于倒三角形:
level=1, 新增了三角形0个。

level=2,新增了边长为1的三角形1个

level=3,新增了边长为1的三角形2个。

level=4,新增了边长为1的三角形3个,边长为2的三角形1个。

level=5,新增了边长为1的三角形4个,边长为2的三角形2个。

level=6,新增了边长为1的三角形5个,边长为2的三角形3个,边长为3的三角形1个。

level=7,新增了边长为1的三角形6个,边长为2的三角形4个,边长为3的三角形2个。

level=8,新增了边长为1的三角形7个,边长为2的三角形5个,边长为3的三角形3个,边长为4的三角形1个。
 ……
这么看可能不直观,我们把每一层新增的倒三角形数都加起来。

level=1,新增0个。

level=2,新增1个。

level=3,新增2个。

level=4,新增4个。

level=5,新增6个。

level=6,新增9个。

level=7,新增12个。

level=8,新增16个。


直接说结论: 每当level为偶数时,新增倒三角形数较上一项新增倒三角形数的差都会+1。

或者可以这样:对于每一level,在该level上新增倒三角形数较上一项上的差=floor((double)level/2)。(floor()是对一个数向下取整)。

所以可以设pd[i]为在增加至第i层时,较第i-1层应该新增的倒三角形数,则pd[i]=pd[i-1]+floor((double)i/2)。

再设d[i]为增加至第i层时总共的倒三角形数,那么d[i]=d[i-1]+pd[i]。

至此,整个算法就明了了。
不过时间复杂度上有些高,我们可以开个简单的记忆化,定义一个maxx,为目前到达过的最大层数,每次向后递推,总从第maxx层开始,当level<maxx时,直接输出z[level]+d[level]。
最后是上代码~
另外这道题在原Oj里要求代码长度小于500b,如果一直不过的话可以考虑一下这方面因素。

 1 #include<bits/stdc++.h>
 2 #define ull unsigned long long
 3 using namespace std;
 4 ull n,maxx=1,pz[50000005],pd[50000005],z[50000005],d[50000005];
 5 ull doit(int k)
 6 {
 7 if(k<=maxx) return z[k]+d[k];
 8 else{for(int i=maxx;i<=k;i++){
 9 pz[i]=pz[i-1]+i;
10 z[i]=z[i-1]+pz[i];
11 pd[i]=pd[i-1]+floor((double)i/2);
12 d[i]=d[i-1]+pd[i];
13 }
14 return z[k]+d[k];
15 }
16 }
17 int main()
18 {
19 cin>>n;
20 int level;
21 z[1]=1;
22 for(int i=1;i<=n;i++){
23 cin>>level;
24 cout<<doit(level)<<endl;
25 if(level>maxx) maxx=level;
26 }
27 }
原文地址:https://www.cnblogs.com/MagicConchh/p/13535954.html