邂逅数塔 | ||||||
| ||||||
Description | ||||||
小胖子总是被人嘲笑,很伤心。正在他伤心的时候,邂逅了数塔,发现数塔整容了。 数塔不像是以前那样随意了,变得仪表堂堂,衣装整齐。数塔再也不是那个只求最大值的数塔了。现在的数塔们是规则化管理,都是由数字1,2,3,...,n组成一个三角形数字塔。比如n=4, 1 1 2 1 2 3 1 2 3 4 现在从第一个点往下走,可以往下,或者往右下,可以组成多种路径。比如n=4时, 路径 1->1->1->1 4 1->1->1->2 5 1->1->2->2 6 1->1->2->3 7 1->2->2->2 7 1->2->2->3 8 1->2->3->3 9 1->2->3->4 10 这里面有3个质数,5,7,7 数塔问小胖子,如果你能求出我们这些数塔里的质数有多少个,我就可以帮你解决烦恼。为了可爱的小胖子,大家一起来帮帮他吧。 | ||||||
Input | ||||||
本题有多组测试数据,每组测试数据占一行。 每行输入一个整数n (1<=n<=41)。 | ||||||
Output | ||||||
输出所有路径里一共有多少质数。 | ||||||
Sample Input | ||||||
4 | ||||||
Sample Output | ||||||
3 | ||||||
Author | ||||||
sunshine@hrbust |
一开始还是呆萌的写了一发DFS,觉得暴力跑1-41还是有可能的,但是用计算器算了一下2^41,默默的放弃。
这个题在计算过程中有这样的一个特点,以至于我们不需要DFS暴力求解。
比如:
1
1 2
我们能够得到到2个数:2 3、
1
1 2
1 2 3
我们能够得到4个数: 3 4 5 6、
当然如果数塔变成n==4的时候:
1
1 2
1 2 3
1 2 3 4
我们就能够得到5个数: 4 5 6 7 7 8 9 10、
观察三组数据:
n=2:2 3
n=3:3 4 5 6
n=4: 4 5 6 7 7 8 9 10
我们发现:
n=3的前2个数是n=2的时候两个数+1得到。n=3的后2个数是n=2的时候两个数+3得到、
n=4的前4个数是n=3的时候前四个数+1得到。n=4的后4个数是n=3的时候四个数+4得到、
通过这个特点我们得到这样的结论:
for(int i=3;i<=41;i++)
{
ma=i*(i-1)/2;//上一行的最大值是i*(i-1)/2;
for(int j=1;j<=ma;j++)
{
if(a[i-1][j])
{
a[i][j+1]+=a[i-1][j];
a[i][j+i]+=a[i-1][j];
}
}
}
然后最后使得素数加和即可。
完整AC代码:
#include<stdio.h>
#include<string.h>
#include<math.h>
using namespace std;
#define ll long long int
#define maxn 1000
int Is_or[1000];
ll a[45][1000];
void init()
{
memset(Is_or,0,sizeof(Is_or));
for(int j=2;j<sqrt(maxn);j++)//
{
if(Is_or[j]==0)//去掉合数的倍数.
for(int k=j+j;k<=maxn;k+=j)//去掉倍数.(把这么些个合数的倍数都标记上这个数不是素数.)
Is_or[k]=1;
}
}
int main()
{
memset(a,0,sizeof(a));
a[1][1]=1;
a[2][2]=1;
a[2][3]=1;
int ma;
for(int i=3;i<=41;i++)
{
ma=i*(i-1)/2;
for(int j=1;j<=ma;j++)
{
if(a[i-1][j])
{
a[i][j+1]+=a[i-1][j];
a[i][j+i]+=a[i-1][j];
}
}
}
init();
int n;
while(~scanf("%d",&n))
{
if(n==1)
{
printf("0\n");
continue;
}
ll output=0;
for(int i=1;i<=((n+1)*n)/2;i++)
{
if(Is_or[i]==0)
{
output+=a[n][i];
}
}
printf("%lld\n",output);
}
}