bzoj4407 于神之怒加强版 莫比乌斯函数

首先运用莫比乌斯函数对原式进行化简,得到:

= i=1 m  j=1 n gcd(i,j) k  d d k  i=1 m/d  j=1 n/d [gcd(i,j)==1] 

 d d k  i=1 m/d  j=1 n/d  p|i,p|j μ(p) k m/kn/k d|k d k μ(k/d) 

然后,令 f(x)= d|k d k μ(k/d)  ,显然可以得到 f(x)  是一个积性函数,如果令辅助数组 g(x)  为x的最小质因数的最高次幂,就可以利用线性筛 O(N)  得到 f  数组。
然后就可以分段计算了。时间复杂度 O(Max+TN − −   ) 
AC代码如下:

#include<iostream>
#include<cstdio>
#define inf 1000000000

using namespace std;
int find(int x){
    int l=1,r=n,mid;
    while (l<r){
        mid=(l+r)>>1; if (hash[mid]<x) l=mid+1; else r=mid;
    }
    return l;
}
void ins(int x,int y){ for (; x<=n; x+=x&-x) c[x]=max(c[x],y); }
int getmax(int x){
    int mx=-inf; for (; x; x-=x&-x) mx=max(mx,c[x]); return mx;
}

int main(){
    scanf("%d",&n); int i;
    for (i=1; i<=n; i++){
        scanf("%d",&a[i]); d[i]=hash[i]=a[i]-i;
    }
    for (i=1; i<=n; i++) scanf("%d",&b[i]);
    for (i=1; i<=n; i++) c[i]=-inf;
    sort(hash+1,hash+n+1); f[1]=1; ins(find(d[1]),1);
    for (i=2; i<=n; i++){
        int t=find(d[i]); f[i]=getmax(t-1)+1; ins(t,f[i]);
    }
    int len=getmax(n); printf("%d ",len);
    return 0;
}
                                        by lych
                                       2016.2.16

你可能感兴趣的:(数论,分块,线性筛,莫比乌斯函数)