标签:分块 ++ 前缀 tar 解法 spl cal getc tps
\[ \mu(i)=\left\{\begin{array}{c} {1 \ \ \ \ \ \ \ \ \ \ \ i=1} \hfill\{(-1)^{k}\ \ \ i=p 1 * p 2 * \ldots * p k} \{0\ \ \ \ \ \ \ \ \ \ \ 其他情况}\hfill \end{array}\right. \]
即不同质数的乘积,则为\((-1)^{k}\) ,\(mu(1) = 1\),其他情况为0
线性筛莫比乌斯函数
int pri[maxn];
int tot = 0;
int mu[maxn];
bool vis[maxn];
void mu_table(int N){//莫比乌斯函数
mu[1] = 1;//i = 1
for(int i = 2; i <= N; i++){
if(!vis[i]){
pri[++tot] = i;
mu[i] = -1;//第二种情况
}
for(int j = 1; j <= tot; j++){
if(i * pri[j] > N)break;
vis[i * pri[j]] = 1;
if(i % pri[j] == 0){
mu[i * pri[j]] = 0;//第三种情况
break;
}else mu[i * pri[j]] = - mu[i];//第二种情况
}
}
}
\((f * g)(n)=\sum_{d | n} f(d) g\left(\frac{n}{d}\right)\)
积性函数:对于任意互质的整数a和b有性质\(f(ab) = f(a) f(b)\)
完全积性函数:对于任意的整数a和b有性质\(f(ab) = f(a) f(b)\)
莫比乌斯函数\(\mu(i)\)和欧拉函数\(\varphi(i)\)都是积性函数
\[ \begin{aligned}&约数形式\ \ F(n)=\sum_{d | n} f(d) \Longrightarrow f(n)=\sum_{d | n} u(d) F\left(\frac{n}{d}\right)\\&倍数形式\ \ F(n)=\sum_{n | d} f(d) \Longrightarrow f(n)=\sum_{n | d} u\left(\frac{d}{n}\right) F(d)\end{aligned} \]
对于一些\(f(n),如果容易求出倍数和或者约数和F(n),那么就可以通过反演求得f(n)的值\)
上面公式详细点就是
\(g(x)\)是给出的式子
进行构造函数\(f(n)\),反演出\(g(n)\)
约数形式\[\begin{aligned} &f(n)=\sum_{d | n} g(d)\&g(n)=\sum_{d | n} \mu(d) f\left(\frac{n}{d}\right) \end{aligned}\]
倍数形式\[\begin{aligned} &f(n)=\sum_{n | d} g(d)\&g(n)=\sum_{n | d} \mu\left(\frac{d}{n}\right) f(d) \end{aligned}\]
举例子:
给出一个式子\(g(x)=\sum_{i=1}^{n} \sum_{j=1}^{m}[g c d(i, j)==d]\)
用第二组式子构造\(f(x) = g(d) + g(2d) + ... +g\left(\left\lfloor\frac{N}{d}\right\rfloor\right)\)
即\(f(d) = \sum_{d|p}g(p)(p≤N)\)
进行反演
\(g(d)=\sum_{d | p} \mu\left(\frac{p}{d}\right) f(p)\)
因为\(\sum_{d|n}f(n)是指所有f(n)中满足d|n的个数 =\left\lfloor\frac{上限}{d}\right\rfloor\)
\(f(x) = \left\lfloor\frac{n}{x}\right\rfloor\left\lfloor\frac{m}{x}\right\rfloor\)
那么答案就是
\(g(d) = \sum_{d|p}\mu(\frac{p}{d})\left\lfloor\frac{n}{p}\right\rfloor\left\lfloor\frac{m}{p}\right\rfloor\)
枚举\(\left\lfloor\frac{p}{d}\right\rfloor = t\)
\(g(d) = \sum_{t = 1}^{min(n,m)}\mu(t)\left\lfloor\frac{n}{td}\right\rfloor\left\lfloor\frac{m}{td}\right\rfloor\)
然后整除分块一波即可
\(\sum_{i=1}^{n}\left\lfloor\frac{n}{i}\right\rfloor\)
普通的方法是\(O(n)\)
但是利用整除分块可以做到\(O(\sqrt{n})\)
因为有很多的\(\left\lfloor\frac{n}{i}\right\rfloor\)具有相同的值,每一个相同的值处于一块状分布
通过打表发现,一个分块的最后一个数是\(n/(n/i)\)所以可以用\(\sqrt{n}\)
for(int l = 1,r; l <= n; l = r + 1){
r = n/(n/l);
ans += (r - l + 1) * (n/l);//这一段的值相同
}
上面的那个式子的解法
传送门
#include <iostream>
#include <cstdio>
#define ll long long
using namespace std;
const int maxn = 5e4 + 5;
int tot = 0;
int mu[maxn];
bool vis[maxn];
int pri[maxn];
int sum[maxn];
int read(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
return f*x;
}
void mu_table(int N){
mu[1] = 1;
for(int i = 2; i <= N; i++){
if(!vis[i]){
pri[++tot] = i;
mu[i] = -1;
}
for(int j = 1; j <= tot; j++){
if(i * pri[j] > N)break;
vis[i * pri[j]] = 1;
if(i % pri[j] == 0){
mu[i * pri[j]] = 0;
break;
}else mu[i * pri[j]] = -mu[i];
}
}
for(int i = 1; i <= N; i++)sum[i] = sum[i - 1] + mu[i];//此处前缀和是为了整除分块
}
int k;
int cal(int a,int b){
int ans = 0;
int mx = a/k;
int my = b/k;
int minn = min(mx,my);
for(int l = 1,r; l <= minn; l = r + 1){
r = min(mx/(mx/l),my/(my/l));
ans += (mx/l) * (my/l) * (sum[r] - sum[l - 1]);
}
return ans;
}
int main(){
int t;
mu_table(50000);
t = read();
while(t--){
int a,b,c,d;
a = read(),b = read(), c = read(),d = read();
k = read();
printf("%d\n",cal(b,d) - cal(b,c-1) - cal(a-1,d)+cal(a-1,c-1));
}
return 0;
}
标签:分块 ++ 前缀 tar 解法 spl cal getc tps
原文地址:https://www.cnblogs.com/Emcikem/p/12191370.html