题目:394
题意:
我们来定义下一个数的素数价值,假设这个数是N(2<=N<=50000),我们可以通过以下两种方法:
1.把当前数字除以某个素数(当然得可以整除),即N = N / p;
2.把当前数字减去某个素数(保证减后结果为正整数),即N = N - p;
这个数字的素数价值是最少得通过多少次以上的方法使得它变成0.
思路:
这题 .... 算我读题不认真吧,反正Wa了好几次。
没想象中复杂,用到了哥德巴赫猜想,任意一个大于2的偶数均可以表示成两个素数之和。
所以对于素数输出1,然后偶数输出2,接着判断为两素数之积的也是输出2,其余的输出3
WA点:不要以为所有操作的素数p均是n的约数,这题没那么复杂。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cmath>
using namespace std;
#define maxn 50010
bool vis[maxn];
int n_prime=0;
int prime[maxn];
int cnt[maxn];
void Prime()
{
memset(vis,true,sizeof(vis));
vis[0]=vis[1]=0;
for(int i=2;i<maxn;i++)
{
if(vis[i])
{
prime[++n_prime]=i;
for(int j=2*i;j<maxn;j+=i)
vis[j]=0;
}
}
//cout<<n_prime<<":"<<prime[n_prime]<<endl;
}
int main()
{
Prime();
for(int i=1;i<maxn;i++)
cnt[i]=3;
for(int i=1;i<maxn;i++)
{
for(int j=1;j<=n_prime;j++)
{
if(i<prime[j])
break;
if(i%prime[j]==0)
{
if(vis[i/prime[j]])
cnt[i]=2;
}
}
}
for(int i=1;i<maxn;i++)
if(vis[i])
cnt[i]=1;
else if(vis[i-2]||i%2==0)
cnt[i]=2;
cnt[0]=0;
cnt[1]=1;
for(int i=2;i<maxn;i++)
cnt[i]+=cnt[i-1];
int t,l,r;
cin>>t;
while(t--)
{
cin>>l>>r;
cout<<cnt[r]-cnt[l-1]<<endl;
}
return 0;
}
咳咳。。
如果把这题第二点去掉,然后把最后结果改成1,那么可以用下面的代码解决了(这是我之前看错题目写的。。。)
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cmath>
using namespace std;
#define maxn 50010
bool vis[maxn];
int n_prime=0;
int prime[maxn];
int cnt[maxn];
void Prime()
{
memset(vis,true,sizeof(vis));
vis[0]=vis[1]=0;
for(int i=2;i<maxn;i++)
{
if(vis[i])
{
prime[++n_prime]=i;
for(int j=2*i;j<maxn;j+=i)
vis[j]=0;
}
}
//cout<<n_prime<<":"<<prime[n_prime]<<endl;
}
int main()
{
Prime();
memset(cnt,0,sizeof(cnt));
int tmp;
for(int i=1;i<maxn;i++)
{
tmp=i;
for(int j=1;j<=n_prime;j++)
{
if(tmp<prime[j])
break;
if(vis[tmp])
{
cnt[i]=1;
break;
}
if(tmp%prime[j]==0)
{
cnt[i]=cnt[tmp/prime[j]]+1;
break;
}
}
}
for(int i=1;i<maxn;i++)
cnt[i]+=cnt[i-1];
int t,l,r;
cin>>t;
while(t--)
{
cin>>l>>r;
cout<<cnt[r]-cnt[l-1]<<endl;
}
return 0;
}