题目描述
XX 摆出了一个难题来考验 YYY。 众所周知,线性筛的一种伪代码如下
输入一个整数 n
申请一个布尔数组 b,初始值全为假
申请一个质数列表 c,初始为空
令 i 从 2 到 n
如果 b[i]为假,那么 c 在尾部增加 i 这个元素
令 j 从头至尾遍历 c 的元素
使 b[i*j]为真
如果 i 为 j 的倍数,那么跳出这层循环
缩进表示语句之间的关系,缩进多的语句嵌套在缩进少的语句中。
但是 XXX 将线性筛的伪代码变成了这样:
输入一个整数 n
申请一个整型数组 b,初始值全为 0
申请一个质数列表 c,初始为空
令 i 从 2 到 n
如果 b[i]为 0,那么 c 在尾部增加 i 这个元素
令 j 从头至尾遍历 c 的元素
使 b[i*j]为 j
如果 i 为 j 的倍数,那么跳出这层循环
现在 XXX 给定整数 k 和 n, YYY 需要回答两个问题:
1:对于未经 XXX 修改的伪代码,输入整数为 n,执行之后,布尔数组 b 中下标在
[k,n]的值为真的个数。
2:对于 XXX 修改后的伪代码,输入整数为 n,执行之后,整型数组 b 中下标在[k,n]
的值的和。
YYY 冷静地思考了一会儿,发现自己并没有什么想法,转而向你求助。你能一眼秒
了此题,加入嘲讽 XXX 的行列吗?
输入
输入文件共一行,两个用空格隔开的正整数 k,n
输出
输出文件共一行,两个用空格隔开的整数。第一个整数为第一个问题的答案,第二
个整数为第二个问题的答案对 998244353 取模的结果
样例输入 1
5 10
样例输出 1
4 9
样例 1 解释
第一个问题的答案 4 为: b[6],b[8],b[9],b[10]为真
第二个问题的答案 9 为: b[6]=b[8]=b[10]=2,b[9]=3
样例输入 2
24788 87347
样例输出 2
56820 605038
数据规模
一看这题,诶以前写过类似的,结果所有地方都是long long,除了最前面的int n,k(我也不知道为啥我写int,可能顺手就打了)然后……100->10
引以为戒
#include<cstdio>
#include<cstring>
typedef long long ll;
ll k,n;
const int N=10000000;
const int mod=998244353;
int iscomp[N+10];
int prime[N+10],p;
void primetable()
{
for(int i=2;i<=N;i++)
{
if(!iscomp[i])prime[p++]=i;
for(int j=0;j<p&&i*prime[j]<=N;j++)
{
iscomp[i*prime[j]]=prime[j];
if(i%prime[j]==0)break;
}
}
}
int b[N+10];
int main()
{
//freopen("linear.in","r",stdin);
//freopen("linear.out","w",stdout);
//freopen("in.txt","r",stdin);
primetable();
scanf("%lld%lld",&k,&n);
for(ll i=0;i<p;i++)
{
if(prime[i]>n)break;
ll l=(k-1)/prime[i]+1,r=n/prime[i];
for(ll j=l;j<=r;j++)
if(j>1)
{
if(prime[i]*j-k<0)continue;
if(b[prime[i]*j-k]>0)continue;
b[prime[i]*j-k]=prime[i];
}
}
ll cnt=0,ans=0;
for(ll i=0;i<=n-k;i++)
{
if(!b[i])continue;
cnt++,ans=(ans+b[i])%mod;
}
printf("%lld %lld\n",cnt,ans);
return 0;
}