反演曾经一直是我不敢搞的一个大坑……
又重新学习了一下反演,并且做了一些习题……
大概基础什么的……我就介绍一点常用的
正经反演的式子有这样两种
$$f(n)=\sum _{d|n}F(d) \mu(\frac{n}{d})$$
以及
$$f(n)=\sum _{n|d} F(d)\mu(\frac{d}{n})$$
很多题都要用关于狄利克雷卷积的一个式子
$\mu \otimes 1 = e$,也即$\sum _{d|n} \mu(d)=[n==1]$
证明的话……我们可以用二项式定理来证,网上有很多证明,我就不证了
基本上,所有题目的转换都会利用这个式子
我们一般会搞一个$[???==1]$,然后套用上面那个关于$\sum\mu$的式子
…………板子题就不放了,每道题都挺水的
一般就是枚举$gcd$,然后判$[gcd==d]$的时候才累加,
然后除掉一个$d$变成$[gcd==1]$,然后套式子.
写一些比较有意思的题目好了。
这题反演的式子还是可以推的……甚至说比较板子
比较好的思想是我们把询问离线按a排序,下标i按照F值排序
然后用树状数组维护答案并且更新
数学与数据结构的优秀结合……
贴代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 typedef long long LL; 6 const int N=100010; 7 const unsigned int inf=0x7fffffff; 8 bool vis[N+10];int tot; 9 unsigned int prime[N],sumd[N+10]; 10 unsigned int tmp1[N+10],tmp2[N+10],mu[N+10],p[N+10]; 11 struct node{unsigned int ans,id,n,m,a;}q[20010]; 12 inline bool mt1(const node &a,const node &b){return a.a<b.a;} 13 inline bool mt2(const int &a,const int &b){return sumd[a]<sumd[b];} 14 inline bool mt3(const node &a,const node &b){return a.id<b.id;} 15 inline void intn() 16 { 17 int k;mu[1]=sumd[1]=1; 18 for(int i=2;i<=N;i++) 19 { 20 if(!vis[i]) 21 { 22 prime[++tot]=tmp2[i]=i; 23 sumd[i]=tmp1[i]=i+1,mu[i]=-1; 24 } 25 for(int j=1;j<=tot&&(k=i*prime[j])<=N;j++) 26 { 27 vis[k]=1; 28 if(i%prime[j]==0) 29 { 30 tmp2[k]=tmp2[i]*prime[j],tmp1[k]=tmp1[i]+tmp2[k]; 31 sumd[k]=sumd[i]/tmp1[i]*tmp1[k]; 32 mu[k]=0;break; 33 } 34 sumd[k]=sumd[i]*sumd[prime[j]]; 35 tmp1[k]=1+prime[j];tmp2[k]=prime[j]; 36 mu[k]=-mu[i]; 37 } 38 } 39 for(int i=1;i<=N;i++)p[i]=i; 40 sort(p+1,p+N+1,mt2); 41 } 42 unsigned int bit[N+10]; 43 inline int lowbit(int a){return a&-a;} 44 inline void add(int pos,unsigned int val){while(pos<=N)bit[pos]+=val,pos+=lowbit(pos);} 45 inline unsigned int query(int pos) 46 {unsigned int ret=0;while(pos)ret+=bit[pos],pos-=lowbit(pos);return ret;} 47 inline unsigned int calc(unsigned int n,unsigned int m) 48 { 49 if(n>m)swap(n,m); 50 unsigned int ret=0,last; 51 for(unsigned int i=1;i<=n;i=last+1) 52 { 53 last=min(n/(n/i),m/(m/i)); 54 ret+=(n/i)*(m/i)*(query(last)-query(i-1)); 55 } 56 return ret; 57 } 58 int main() 59 { 60 intn();int top=1,t;scanf("%d",&t); 61 for(int i=1;i<=t;i++) 62 q[i].id=i,scanf("%d%d%d",&q[i].n,&q[i].m,&q[i].a); 63 sort(q+1,q+t+1,mt1); 64 for(int i=1;i<=t;i++) 65 { 66 while(top<=N&&sumd[p[top]]<=q[i].a) 67 { 68 for(int k=1;k*p[top]<=N;k++) 69 add(k*p[top],mu[k]*sumd[p[top]]); 70 top++; 71 } 72 q[i].ans=calc(q[i].n,q[i].m); 73 } 74 sort(q+1,q+t+1,mt3); 75 for(int i=1;i<=t;i++) 76 printf("%d\n",q[i].ans&inf); 77 }