SGU116 Index of super-prime
题目大意:
序列P1, P2, … ,Pk, …为超级素数序列。超级素数是指一个数在本身是素数的基础上,他在素数序列里的下标也是素数。例如3就是超级素数,但7不是。如果一个数不能由一个或多个超级素数相加而得,那么这个数的超级素数目录是0。但是如果存在这样的序列,那么这个数的超级素数目录就是这个序列的最小长度。你的任务是照出这个数的超级素数目录,以及这个序列。
输入:
一个正整数N(0<N<=10000)
输出:
输出超级素数目录,并且如果序列存在的话,在另一行按不上升的顺序输出该序列。
样例输入:
6
样例输出:
2
3 3
这道题还是很基础的。
一个素数一定大于他在素数序列里的下标(这是常识!)
首先我们要求出超级素数,这个只需在欧拉筛里做个小小的改进。
下一步就是用这个序列数字N。
最基础的背包DP...
设f[i]————数字i的超级素数目录。
转移方程:f[i]=MIN(f[i-super_prime[j]]+1)(super_prime[]为超级素数序列);
设pre[i]等于对应的超级素数super_prime[j];
输出的时候倒着输出即可。
注意事项:
1.输出顺序(仔细看题!),如果错了的话你会WA在Test8(所以前面七个点心态在哪?)
2.超级素数在列举的时候倒序列举(这样可以优先使用大素数)
下面附上我的代码:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <stdbool.h>
int n;
bool check[10030];
int super_prime[10030],prime[10030],super_total,total;
int f[10030],pre[10030],print[10030],t;
void super_eular() //超级欧拉筛
{
int i,j;
check[0]=check[1]=false;
for (i=2;i<=n;i++)
{
if (check[i])
{
prime[++total]=i;
if (check[total])
super_prime[++super_total]=i; //记录超级素数序列
}
for (j=1;j<=total;j++)
{
if (i*prime[j]>n)
break;
check[i*prime[j]]=false;
if (i%prime[j]==0)
break;
}
}
return ;
}
void dp() //背包
{
int i,j;
for (i=1;i<=n;i++)
for (j=super_total;j>=1;j--)
if (i-super_prime[j]>=0)
if (f[i-super_prime[j]]+1<f[i])
{
f[i]=f[i-super_prime[j]]+1;
pre[i]=super_prime[j];
}
return ;
}
void init()
{
int i;
memset(check,true,sizeof(check));
scanf("%d",&n);
for (i=1;i<=n;i++)
f[i]=1000000000;
super_eular();
dp();
if (f[n]!=1000000000)
{
printf("%d\n%d",f[n],pre[n]);
for (i=n-pre[n];i;i=i-pre[i])
printf(" %d",pre[i]); //输出序列
printf("\n");
}
else
printf("0");
return ;
}
int main()
{
init();
return 0;
}