狄利克雷
一大堆带着 Dirichlet 的东西。原计划是整点拉格朗日反演,但是看见 jijidawang 博客给我来劲了,遂改。
Dirichlet 前缀和
给你一个函数(或者数列)
当然可以枚举倍数做到
实际上把每个质因数当成一维,然后做高维前缀和就行了。代码就这点。
for(int i=1;i<=p[0];i++){
for(int j=1;p[i]*j<=n;j++){
a[p[i]*j]+=a[j];
}
}
复杂度
类似的有 Dirichlet 差分(就是卷
for(int i=1;i<=p[0];i++){
for(int j=n/p[i];j;j--){
a[p[i]*j]-=a[j];
}
}
同样有后缀和(枚举倍数求和)以及后缀差分:
for(int i=1;i<=p[0];i++){
for(int j=n/p[i];j;j--){
a[j]+=a[p[i]*j];
}
}
for(int i=1;i<=p[0];i++){
for(int j=1;j*p[i]<=n;j++){
a[j]-=a[j*p[i]];
}
}
P2714 四元组统计
基础应用。对于
#include <iostream>
#include <algorithm>
#include <cstdio>
#define int long long
using namespace std;
int n,a[10010],p[10010];
bool v[10010];
void get(int n){
for(int i=2;i<=n;i++){
if(!v[i])p[++p[0]]=i;
for(int j=1;j<=p[0]&&i*p[j]<=n;j++){
v[i*p[j]]=true;
if(i%p[j]==0)break;
}
}
}
signed main(){
get(10000);
while(~scanf("%lld",&n)){
int mx=0;
for(int i=1;i<=n;i++){
int x;scanf("%lld",&x);a[x]++;
mx=max(mx,x);
}
for(int i=1;i<=p[0];i++){
for(int j=mx/p[i];j;j--){
a[j]+=a[p[i]*j];
}
}
for(int i=1;i<=mx;i++)a[i]=1ll*(a[i]-3)*(a[i]-2)*(a[i]-1)*a[i]/24;
for(int i=1;i<=p[0];i++){
for(int j=1;j*p[i]<=mx;j++){
a[j]-=a[p[i]*j];
}
}
printf("%lld\n",a[1]);
for(int i=1;i<=mx;i++)a[i]=0;
}
return 0;
}
gcd/lcm 卷积
怎么算?其实可以类似地构造 DFT 和 IDFT。事实上,我们有:
也就是后缀和。那么做一遍高维后缀和,对应点乘,然后后缀差分回去就行了。
同样的,
复杂度
狄利克雷生成函数
是这个形式:
看起来很奇怪,
这就比较优美。
下面是一些常见数论函数的狄利克雷生成函数:
显然是 。这也是狄利克雷生成函数的单位元。
也就是 。它是
换成质数幂处乘积的形式也就是
这个在质数幂处乘积表示下, 时为 , 时为 ,其他为 ,也就是
黎曼
显然是
5.
仍然观察质数幂处取值:
卷积一下,是 。
一个应用:筛
显然是
就是幂函数的二阶差分,也就是
运算
首先是卷积。一般枚举倍数,
假如说我们把
然后把每个函数分别卷到
那么这就是
然后是求逆。假设
当然也可以按照上边的方法
导数和积分。单项求导试试看:
啊这,
一般的定义是把系数
对数和指数。对数仍然定义为
然后是指数。设
这玩意其实可以直接算了。
下面的代码是loj6713的,是狄利克雷快速幂。
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
const int mod=998244353;
int n,k,g[1000010],f[1000010];
int qpow(int a,int b){
int ans=1;
while(b){
if(b&1)ans=1ll*ans*a%mod;
a=1ll*a*a%mod;
b>>=1;
}
return ans;
}
int p[1000010],cnt[1000010];
bool v[1000010];
void get(int n){
for(int i=2;i<=n;i++){
if(!v[i])p[++p[0]]=i,cnt[i]=1;
for(int j=1;j<=p[0]&&i*p[j]<=n;j++){
v[i*p[j]]=true;
cnt[i*p[j]]=cnt[i]+1;
if(i%p[j]==0)break;
}
}
}
void div(int f[],int g[],int n){
int inv=qpow(g[1],mod-2);
for(int i=1;i<=n;i++){
f[i]=1ll*inv*f[i]%mod;
for(int j=2;i*j<=n;j++){
f[i*j]=(f[i*j]-1ll*f[i]*g[j]%mod+mod)%mod;
}
}
}
void dao(int f[],int n){
for(int i=1;i<=n;i++)f[i]=1ll*cnt[i]*f[i]%mod;
}
void jifen(int f[],int n){
for(int i=1;i<=n;i++)f[i]=1ll*qpow(cnt[i],mod-2)*f[i]%mod;
}
void getln(int f[],int g[],int n){
for(int i=1;i<=n;i++)g[i]=1ll*cnt[i]*f[i]%mod;
div(g,f,n);
jifen(g,n);
}
void exp(int f[],int g[],int n){
g[1]=1;
for(int i=1;i<=n;i++){
if(cnt[i])g[i]=1ll*qpow(cnt[i],mod-2)*g[i]%mod;
for(int j=2;i*j<=n;j++){
g[i*j]=(g[i*j]+1ll*f[j]*cnt[j]%mod*g[i])%mod;
}
}
}
int main(){
scanf("%d%d",&n,&k);
get(n);
for(int i=1;i<=n;i++)scanf("%d",&f[i]);
getln(f,g,n);int inv=qpow(k,mod-2);
for(int i=1;i<=n;i++)g[i]=1ll*g[i]*inv%mod,f[i]=0;
exp(g,f,n);
for(int i=1;i<=n;i++)printf("%d ",f[i]);
printf("\n");
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】