Description
问题来自于一个精彩的故事:
有三个数学家,A,B与C。A选了两个正整数x与y满足x<=y。然后,A将x+y的值告诉了B,A又将x*y的值告诉了C。B与C都不知道x与y分别是什么,也不知道对方得到的值是什么。但B和C知道A告诉B的值是某两个正整数的“和”而告诉C的值是这两个数的“积”。而且这三个数学家的数学功底足够好。下面是B与C进行的对话:
B:“我确定你一定没有百分百的把握猜中我得到的数。” C:“谢谢你的提示。现在我能确定你获得的数是 S。” 故事结束,回到问题。
这个故事中一共涉及3个未知参数x,y与S,其实由于S=x+y,所以实际一共只有两个未知参数而已。你可以带入一些正整数让这个故事没有逻辑漏洞。现在问题来了,在区间[L,R]上存在多少个数值t,使S=t时能找到对应的x与y,并让这个故事成立。输出这些t的和(1<=L<=R<=5,000,000)。
Input
多组测试数据,第一行一个整数T,表示数据个数,其中1<=T<=10.
之后有T行,每行两个数L与R,表示一组询问,其中1<=L<=R<=5,000,000.
Output
输出T行,每行一个整数,即[L,R]区间中所有符合条件的S的和。
Sample Input
3
30 33
8 11
40 43
Sample Output
33
19
0
题解
这题很有意思啊
首先考虑 怎么确定 是不能 知道的,显然是 的数不是质数+1
因为如果 的数是个质数,他只有一种分解方式…
然后我们再来观察C是怎么确定的
设 的数是
设 的某种拆分方式是
显然是只有一种拆分使得 不是质数
知道 是个合数
可以知道 这组拆分是合法的,因为 显然不是质数+1
这样我们只需要知道一个数的某个拆分不是质数就可以知道他不合法
枚举约数,这个可以调和级数 把不合法的筛出来
然后就做完了…
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#include<bitset>
#define LL long long
#define mp(x,y) make_pair(x,y)
using namespace std;
inline int read()
{
int f=1,x=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
inline void write(LL x)
{
if(x<0)putchar('-'),x=-x;
if(x>9)write(x/10);
putchar(x%10+'0');
}
inline void pr1(int x){write(x);printf(" ");}
inline void pr2(LL x){write(x);puts("");}
bool v[5000005];int pr[5000005],plen;
void getpr()
{
memset(v,true,sizeof(v));v[1]=false;
for(int i=2;i<=5000000;i++)
{
if(v[i])pr[++plen]=i;
for(int j=1;j<=plen&&i*pr[j]<=5000000;j++)
{
v[i*pr[j]]=false;
if(!(i%pr[j]))break;
}
}
}
LL sum[5000005];
int main()
{
getpr();
for(int i=1;i<=5000000;i++)sum[i]=i;
for(int i=2;i<5000000;i++)
for(int j=i;(LL)i*j<=5000000;j++)
if(!v[i+j-1])sum[i*j+1]=0;
for(int i=1;i<=5000000;i++)if(v[i])sum[i+1]=0;
sum[1]=sum[2]=0;
for(int i=1;i<=5000000;i++)sum[i]=sum[i-1]+sum[i];
int T=read();while(T--)
{
int l=read(),r=read();
pr2(sum[r]-sum[l-1]);
}
return 0;
}