codeforces round 388 div2的A题
A. Bachgold Problem
题意问输入的n最有有多少个素数加起来组成,素数可以重复使用,那这题用贪心,从2开始算起,因为你要求素数最多的话,肯定是越小的个数越多,做完之后,突然发现根本不用打表,n>=2,要么是奇数,要么是偶数,偶数就全2,奇数就把一个2换成3就可以了,居然如此简单。。。。但当时做的时候真的是闪出来素数打表,这就是不用脑地套用习惯思维啊,应该每道题好好地去分析题目特性。
第一次做AC代码
#include <iostream>
#include <cstring>
using namespace std;
typedef long long int ll;
const int maxn = 100005;
bool p[maxn];//0 means prime
int primeNum[maxn];
void setPrime()
{
memset(primeNum,0,sizeof(primeNum));
memset(p,0,sizeof(p));
for(ll i=2;i<maxn;++i){
if(!p[i]){
for(ll j=i*i;j<maxn;j+=i)p[j]=1;
}
}
}
int main()
{
setPrime();
int n;
scanf("%d",&n);
int ans = 0;
for(int i=2;i<=n;++i){
if(!p[i] && n-i>=0){
primeNum[i] = n/i;
ans = ans + primeNum[i];
n = n- n/i*i;
}
}
if(n>0){
if(primeNum[n]){
ans++;
primeNum[n]++;
}else{//n==1
primeNum[2]--;
primeNum[3]++;
}
}
printf("%d\n",ans);
for(int i=2;i<maxn;++i){
while(primeNum[i]--)
printf("%d ",i);
}
printf("\n");
return 0;
}
发现奇偶规律之后,从打表变成了线性时间
#include <iostream>
using namespace std;
typedef long long int ll;
const int maxn = 100005;
int main()
{
int n;
scanf("%d",&n);
int ans = n/2;
printf("%d\n",ans);
int two = n/2,three = 0;
if(n%2)two--,three++;
while(two--)printf("2 ");
while(three--)printf("3 ");
printf("\n");
return 0;
}
时间从31ms变成了30ms????难道是printf慢吗?,有兴趣的朋友可以改用putchar试试。
既然说到了素数打表,顺便记录一下网上的接近线性的高效打表方法
#include<iostream>
#include<string.h>
#include<stdio.h>
#define maxn 10000000
bool visit[maxn+1000000];
int prime[maxn],n; //prime的大小大概估计一下再开数组。大概是(x/lnx)
void getprime()
{
memset(visit, false, sizeof(visit));
int num = 0;
for (int i = 2; i <= n; ++i)
{
if ( !visit[i] ) prime[++num] = i;
for (int j = 1; (j <= num) && (i * prime[j] <= n) ; j++)
{
visit[ i * prime[j] ] = true;
//由 i 和 prime[j] 相乘组成的合数赋为true,注意i不一定为素数,但prime[j] 是素数
if (i % prime[j] == 0) break;
/*此处是重点,避免了很多的重复判断,比如i=9,现在素数是2,3,5,7,进入二重循环,visit[2*9]=1;visit[3*9]=1;这个时候9%3==0,要跳出。因为5*9可以用3*15来代替,如果这个时候计算了,i=15的时候又会被重复计算一次,所以这里避免了重复大量运算。*/
}
}
}
int main()
{
scanf("%d",&n);
getprime();
return 0;
}