Primes Problem HDU 5104 打表大法好啊~~



Primes Problem

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1439    Accepted Submission(s): 610


Problem Description
Given a number n, please count how many tuple(p1, p2, p3) satisfied that p1<=p2<=p3, p1,p2,p3 are primes and p1 + p2 + p3 = n.
 

Input
Multiple test cases(less than 100), for each test case, the only line indicates the positive integer n(n10000) .
 

Output
For each test case, print the number of ways.
 

Sample Input
   
   
   
   
3 9
 

Sample Output
   
   
   
   
0 2
 

Source
BestCoder Round #18

首先素数肯定是要打出一个表的。。。。。
然后就可以有两个选择:
1:用两个循环,判断N减去两个素数的值是否为素数,如果是,方法加1——这里面有个坑,这三个素数是有顺序的而且可以相等,这时候就得动脑筋想一下
有两个素数相等的情况与三个数相等的情况对结果的影响了,结合代码解释:
#include <iostream>
#include <ctime>
using namespace std;

bool primelist[10005];//这个表用来判断是否为素数--真、不是素数,假、是素数
int prime[4000];//这个表用来存储1~1000000中的素数
int n,p1,p2,p3,i,j,k,flag,m;

int creatlist()//素数打表不解释。。。
{
   int i,j;
   primelist[0] = primelist[1] = true;

   for(i = 4;i <10005;i+=2)
        primelist[i] = true;

   for(i = 3;i < 4000;i++)
    if(!primelist[i])
    for(j = i * i;j < 10005;j+=i)
        primelist[j] = true;

   j = 0;
   for(i = 0;i <10000;i++)//提取素数存到prime中
    if(!primelist[i])
    prime[j++] = i;

    return j;//返回素数的个数
}

int main()
{
    k = creatlist();

    while(cin >> n)
    {
        flag = 0;
        for(i = 0;i < k;i++)//两重循环,如果p1 != p2 != p3,那么这一组数据会被计数六次(因为循环是从最小的素数开始的)在草稿纸上演算一次就知道啦
        {
            m = n - prime[i];
            p1 = prime[i];
            if(m <= 0) break;//当素数已经大于N时,后面的素数肯定不会满足了,跳出
            for(j = 0;j < k;j++)
            {
                p2 = prime[j];
                p3 = m - prime[j];
                if(p3 <= 0) break;//同上
                else if(!primelist[p3])//差值是素数,满足,开始计数
                {
                    if((p1 == p2 && p1 != p3) || (p1 == p3 && p1 != p2) || (p2 == p3 && p1 != p2)) flag++;//当俩个数相等时(可以草稿纸演示),只会被记录三次,要使它变为6,所以每次要额外加一
                    else if(p1 == p2 && p2 == p3) flag+=5;//当三个数都相等时,只会被计数一次,所以额外加个5————因为结果会除6
                    flag++;//只要进入本循环,就要加一
                    //cout << p1 <<" " << p2 << " " << p3 << endl;//调试语句
                }
            }
        }
        cout << flag / 6 << endl;//每组数据都会重复计数6次,所以结果除6
    }
    return 0;
}//看不懂的童鞋多看几遍就好了。。。。
 
 
就是把结果打表————把所有素数求出来,把以三个素数相加的且小于1000000的值为下标的元素的值累加一,即a【N】的值代表组成N会有多少种方法。最后直接输出数组元素的值就好了,再贴一码。。。这个不是自己打的,讨论区来的。。。。解释是自己加的
#include<stdio.h>
#include<math.h>
#include<string.h>
int N,rel[11000],prim[11000],sushu[11000];
int main()
{
	int i,j,k,t=0;
	memset(prim,0,sizeof(prim));
	memset(rel,0,sizeof(rel));
	memset(sushu,0,sizeof(sushu));
	for(i=2;i<10000;i++)//素数打表,不解释,这个方法比我的简单一点 = = 不过原理还是一样————直接赋值会比用取余运算判断素数要快
	{
		if(!prim[i])
		{
			sushu[t++]=i;
			for(j=2;j<10000;j++)
			{
				if(i*j>=10000)break;
				prim[i*j]=1;
			}
		}		
	}
	for(i=0;i<t;i++)//三个循环遍历所有素数情况
	for(j=i;j<t;j++)//从i开始避免出现重复的数据组成情况,所以最后的结果不需要像第一种情况除6
	for(k=j;k<t;k++)//从j开始原因同上
	{
		if(sushu[i]+sushu[j]+sushu[k]>10000)break;//三个素数之和大于上限了,肯定不满足
		rel[sushu[i]+sushu[j]+sushu[k]]++;//每组成一个数字,以该数据为下标的元素累加一,代表多出一种组成方法
	}
	while(scanf("%d",&N)!=EOF)
	{
		printf("%d\n",rel[N]);
	}
	return 0;
}


你可能感兴趣的:(ACM,HDU,杭电)