好吧,在比赛的时候在做471D,鼓捣了半天没弄出来。。。最后比完赛发现是471D的KMP在写的时候一个小细节没注意。。。。嘛,不过这道题目我也是想了一会儿的,首先我觉得这个应该是找规律的一道题目吧。
好吧,首先想摆到某一层之后卡片数有什么特点,设摆到了第L层,此时有K个小屋(也就是“∧”型),我们可以通过这两个假设把总卡片数推出来,那么,总的卡片数应该就是3*K - L,因为本来有K个小屋,每个小屋上有一个天花板,应该是3K,但是每一层最左边(或者最右边)的小屋是没有天花板的,因此每一层就要减1。
那么,我们此时就得到了判定在某一数量的卡片n下,能否摆在第L层的的一个判定公式,假若n+L能够被3整除,那么n就可以摆L层(但是不一定能够摆在L-1层)。有了这个之后,只需要把最大的层数求出来,然后对每一层进行枚举即可。
求最大层数L,我们就需要知道在层数为L的情况下最少能够摆多少张卡片。我们可以发现,第一次需要1个小屋,第二层需要3个,第三层需要6个,。。。很轻易的推导出需要小屋数量的通项公式是(L + 1)*L / 2,既然最少需要这么多小屋,而且总的卡片数满足n + L % 3 == 0,我们带到我们的式子里面去,又是一个关系。 3*(L + 1)* L /2 - L<= n。这个就是n满足的一个关系式, n要大于等于其最大层数的最少卡片数。然后我们把L解出来,向下取整,便是最大层数,然后枚举即可,枚举的代码我写在注释里面了,我真正的代码不是这么写的。。。
Tips:judge把n的每一位加起来,用于判断能否被3整除,因此,最终变成了判定区间【judge +1,judge+high】内有多少个数能够被3整除
#include<cstdio>
#include<cmath>
using namespace std;
long long n,ans,high,judge;
char str[15];
int main(){
scanf("%lld",&n);
high=floor((-1.0+pow(1+24*n,0.5))/6);
sprintf(str,"%lld",n);
for(int i=0;str[i];++i)
judge+=str[i]-'0';
printf("%lld\n",(judge+high)/3-judge/3);
// for(int times=1;times<=high;++times){
// ++judge;
// if(judge%3==0)
// ++ans;
// }
// printf("%lld\n",ans);
return 0;
}