简单求值 主要关键是了解一下欧拉函数
冬令营时接触了一下欧拉函数 当时看这题发现看得懂题面然后尝试做了一下 发现我低估了O(n2)的威力……于是回来之后了解了一下欧拉函数 还真是个优美的小别致……
欧拉函数(简简简略)
1.(定义)欧拉函数是小于x的整数中与x互质的数的个数,一般用φ(x)表示。特殊的,φ(1)=1。
(既然φ(1)=1为什么不直接定义成小于等于x的整数呢…… )
2.(公式) 通式:
φ
(
x
)
=
x
∏
i
=
1
n
(
1
−
1
p
i
)
φ(x)=x\prod_{i=1}^n{(1-\frac{1}{p_i})}
φ(x)=xi=1∏n(1−pi1)
φ(1)=1。其中
p
i
{p_i}
pi为x的质因数,x是正整数。
关于求值:
那要求1~n所有数的欧拉函数呢?可以用埃拉托斯特尼筛的思想,每次找到一个质数,就把它的倍数更新掉。这个复杂度虽然不是O(n),但还是挺快的(据说是O(n*ln ln n)。
——来自 https://blog.csdn.net/liuzibujian/article/details/81086324
代码实现:
void euler(int n)
{
for (int i=1;i<=n;++i)
phi[i]=i; //初值
for (int i=2;i<=n;++i)
if (phi[i]==i) //phi[i]==i 即i是质数
for (int j=i;j<=n;j+=i)
phi[j]=phi[j]/i*(i-1); //给i的倍数累乘上(1-1/i)
}
与素数筛同理 欧拉函数的求值也可以用欧拉筛来做 (但是我觉得埃式筛法好理解好记(还短(…)
所以决定就是你了!Sieve of Eratosthenes!
AC不WA:
#include<stdio.h>
const int MAX_N=3000000;
long long phi[MAX_N+1]; //由于题意要求是范围内累加 会爆int
void vivi(int n) //埃式筛法离线求函数值
{
phi[0]=0;
int i, j;
for(i=1;i<=n;i++)
phi[i]=i;
for(i=2;i<=n;i+=2)
if(phi[i]==i)
for(j=i;j<=n;j+=i)
phi[j]=phi[j]/i*(i-1);
for(i=1;i<=n;++i) //简单累加,方便后续范围求值
phi[i]+=phi[i-1];
}
int main()
{
vivi(MAX_N);
int a,b;
while(~scanf("%d %d",&a,&b))
printf("%lld\n",phi[b]-phi[a-1]);
return 0;
}
组合数求因子数 本来想像冬令营里一样离线求好C再拆因子 不过数据太大了好像会T 那就换个求法XD
设n!中素因子p的个数为:a=n / p+n / (p2)+…+n / (pk)+…
那么(n/p)!中素因子p的个数为:b = n/(p2)+…+n/(pk)+…
很显然a=b+n/p,因此可以利用上述递推公式预处理出所有的j!中每个素因子的个数。
——来源 https://blog.csdn.net/lizhiwei2017/article/details/81303911
代码实现:
void ESpp(int n) //欧拉素数筛 筛出1~431的素数
{
memset(ispp,-1,sizeof(ispp)); //初始化为真
int i,j;
for(i=2;i<n+1;++i)
{
if(ispp[i])
pp[++num]=i;
for(j=1;j<=num;++j)
{
if(i*pp[j]>n+1)break;
ispp[i*pp[j]]=0;
if(i%pp[j]==0)break;
}
}
}