签到题
题目背景
这是一道签到题!
建议做题之前仔细阅读数据范围!
题目描述
我们定义一个函数:qiandao(x)为小于等于x的数中与x不互质的数的个数。
这题作为签到题,给出l和r,要求求∑i=lrqiandao(i) mod 666623333\sum_{i=l}^r qiandao(i)~mod~666623333∑i=lrqiandao(i) mod 666623333。
输入格式
一行两个整数,l、r。
输出格式
一行一个整数表示答案。
样例 #1
样例输入 #1
233 2333
样例输出 #1
1056499
样例 #2
样例输入 #2
2333333333 2333666666
样例输出 #2
153096296
提示
对于30%的数据,l,r≤103l,r\leq 10^3l,r≤103。
对于60%的数据,l,r≤107l,r\leq 10^7l,r≤107。
对于100%的数据,1≤l≤r≤10121 \leq l \leq r \leq 10^{12}1≤l≤r≤1012,r−l≤106r-l \leq 10^6r−l≤106。
最近luogu更新了,总算是干了一件好事,题目一键即可移植。
前置知识,phi的一些相关性质
题目分析:
我们可以先看这个数据范围,101210^{12}1012直接用筛法一定会TLE,于是我们就可以从区间长度这里突破,1e6的数据。我们其实从题目中看出,这是一个跟欧拉函数相关的题目,我们知道,欧拉函数是一个积性函数,所以我们可以很容易的想到用此性质来求出此区间内的所有欧拉函数总和。
首先我们可以先筛出1~1e6范围内的素数,因为l和r在1 ~ 1e12中,所以在此区间内的数均可以用小于1e6的因数表示出来,这个时候其实还有一个例外需要注意以下,在l ~ r的数中,我们其实也还是会有素数的存在,而且在这种情况下这个大素数的指数只有可能为一,那么怎么办呢,这个时候我们就可以分解一下,如果没有被分解到一的数,那么这个数还要在进行一次phi的计算。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
const ll mod=666623333,maxn=1e6+11,N=1e5+11;
ll prime[maxn],vis[maxn],len,vis1[maxn];
ll l,r;
ll ans;
int main() {
scanf("%lld%lld",&l,&r);
for(int i=2; i<=1e6; ++i) {
if(!vis[i]) prime[++len]=i;
for(int j=1; j<=len&&prime[j]*i<=1e6; ++j) {
vis[prime[j]*i]=1;
if(i%prime[j]==0) break;
}
}
//处理处1至1e6的素数 利用欧拉函数的性质对其倍数求取素数个数
for(ll i=l; i<=r; ++i) vis[i-l]=vis1[i-l]=i;
for(int i=1; i<=len&&prime[i]*prime[i]<=r; ++i)
{
ll p=prime[i];
for(ll j=(p-l%p)%p; j<=r-l; j+=p)
{ //类似于hash的思想
vis[j]/=p,vis[j]*=(p-1);
while(vis1[j]%p==0)
vis1[j]/=p;
}
}
for(int i=0; i<=r-l; ++i)
{
if(vis1[i]!=1) vis[i]/=vis1[i],vis[i]*=(vis1[i]-1);
ans=(ans+i+l-vis[i])%mod;
}
printf("%lld",ans);
return 0;
}