莫比乌斯反演 hdu 4676 Sum Of Gcd

来源:互联网 发布:淘宝月销量怎么算 编辑:程序博客网 时间:2024/04/29 09:43

Sum Of Gcd

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 513    Accepted Submission(s): 222


Problem Description
Given you a sequence of number a1, a2, ..., an, which is a permutation of 1...n.
You need to answer some queries, each with the following format:
Give you two numbers L, R, you should calculate sum of gcd(a[i], a[j]) for every L <= i < j <= R.
 

Input
First line contains a number T(T <= 10),denote the number of test cases.
Then follow T test cases.
For each test cases,the first line contains a number n(1<=n<= 20000).
The second line contains n number a1,a2,...,an.
The third line contains a number Q(1<=Q<=20000) denoting the number of queries.
Then Q lines follows,each lines contains two integer L,R(1<=L<=R<=n),denote a query.
 

Output
For each case, first you should print "Case #x:", where x indicates the case number between 1 and T.
Then for each query print the answer in one line.
 

Sample Input
153 2 5 4 131 52 43 3
 

Sample Output
Case #1:1140
 

Source
2013 Multi-University Training Contest 8



题意:有一个数列,是1~n的排列。然后有Q个询问,询问[L,R]中所有gcd(a[i],a[j]) i<j 之和。


思路:


代码:

#include <iostream>#include <cstdio>#include <string.h>#include <cstring>#include <vector>#include <cmath>#include <algorithm>#include <queue>using namespace std;#define LL long long#define clr(a,x) memset(a,x,sizeof(a))#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1#define mp make_pair#define Fout(file) freopen(file,"w",stdout)#define Fin(file) freopen(file,"r",stdin)const int maxn=20000+5;int n,Q;struct Point{    int x,y,id;    Point(int x=0,int y=0,int id=0)        :x(x),y(y),id(id) { }    bool operator<(const Point&a) const    {        if(a.x==x) return y>a.y;        return x<a.x;    }}pt[maxn],cpy[maxn];struct SegmentTree{    int minimal[maxn<<2],id[maxn<<2];    int tree_size;    void PushUp(int rt)    {        if(minimal[rt<<1]>minimal[rt<<1|1]) minimal[rt]=minimal[rt<<1|1],id[rt]=id[rt<<1|1];        else minimal[rt]=minimal[rt<<1],id[rt]=id[rt<<1];    }    void init() { clr(minimal,0x3f); clr(id,-1); }    void update(int p,int x,int id)    {        p+=tree_size; if(minimal[p]<=x) return;        minimal[p]=x; this->id[p]=id;        p>>=1;        while(p>=1) {            PushUp(p);            p>>=1;        }    }    int query(int l,int r)    {        l+=tree_size; r+=tree_size;        int ret=-1;        while(l<=r) {            if(l&1) {                if(id[l]!=-1) {                    if(ret==-1) ret=id[l];                    else if(pt[ret].x+pt[ret].y>pt[id[l]].x+pt[id[l]].y)                        ret=id[l];                }                ++l;            }            if(~r&1) {                if(id[r]!=-1) {                    if(ret==-1) ret=id[r];                    else if(pt[ret].x+pt[ret].y>pt[id[r]].x+pt[id[r]].y)                        ret=id[r];                }                --r;            }            l>>=1; r>>=1;        }        return ret;    }}segtree;struct Edge{    int u,v,cost;    Edge(int u=0,int v=0,int cost=0)        :u(u),v(v),cost(cost) { }    bool operator<(const Edge&e) const { return cost<e.cost; }}edges[maxn<<3];int e_cnt;struct Node{    int v;    Node *next;}*first[maxn],edge[maxn<<1];int ptr;void add(int u,int v){    edge[++ptr].v=v;    edge[ptr].next=first[u];    first[u]=&edge[ptr];}int a[maxn],b[maxn];bool cmp_a(int x,int y) { return a[x]<a[y]; }int Bin(int x,int l,int r){    int m;    while(l<=r) {        m=(l+r)>>1;        if(a[b[m]]==x) return m;        else if(a[b[m]]<x) l=m+1;        else r=m-1;    }    return l;}int find(int x){    if(x==b[x]) return x;    return b[x]=find(b[x]);}void swap(int&a,int&b) { a^=b; b^=a; a^=b; }void MST(int n){    e_cnt=0;    for(int dir=0;dir<4;++dir) {        if(dir==1||dir==3) for(int i=0;i<n;++i) swap(pt[i].x,pt[i].y);        else if(dir==2) for(int i=0;i<n;++i) pt[i].x=-pt[i].x;        sort(pt,pt+n);        segtree.init();        for(int i=0;i<n;++i) a[i]=pt[i].y-pt[i].x,b[i]=i;        sort(b,b+n,cmp_a);        int c=1;        for(int i=1;i<n;++i)        if(a[b[i]]!=a[b[i-1]]) b[c++]=b[i];        int & sz=segtree.tree_size;        sz=1; while(sz<c) sz<<=1; --sz;        for(int i=n-1;i>=0;--i) {            int h=Bin(pt[i].y-pt[i].x,0,c-1)+1;            int x=segtree.query(h,c);            if(x!=-1) edges[e_cnt++]=Edge(pt[i].id,pt[x].id,pt[x].y+pt[x].x-pt[i].x-pt[i].y);            segtree.update(h,pt[i].x+pt[i].y,i);        }    }    sort(edges,edges+e_cnt);    for(int i=0;i<n;++i) b[i]=i;    clr(first,0); ptr=0;    int len=0; int rest=n-1;    for(int i=0;i<e_cnt;++i) {        Edge&e=edges[i];        if(find(e.u)==find(e.v)) continue;        b[find(e.u)]=find(e.v);        add(e.u,e.v); add(e.v,e.u);        len+=e.cost;        if(--rest==0) break;    }}LL u[maxn],w[maxn];int factor[maxn][85],sz[maxn];void divide_factor(int x){    sz[x]=0;    for(LL i=1;i*i<=x;++i) {        if(x%i) continue;        factor[x][sz[x]++]=x/i;        if(i!=x/i) factor[x][sz[x]++]=i;    }}int cal_mu(int x){    int odd=1;    for(LL i=2;i*i<=x;++i) {        int cnt=0;        while(x%i==0) {            x/=i;            ++cnt;        }        if(cnt>1) return 0;        else if(cnt==1) odd=-odd;    }    if(x>1) odd=-odd;    return odd;}void pre_init(){    u[1]=1;    factor[1][0]=1; sz[1]=1;    for(int i=2;i<=20000;++i) {        divide_factor(i);        u[i]=cal_mu(i);    }    for(int i=1;i<=20000;++i) {        w[i]=0;        for(int j=0;j<sz[i];++j) {            w[i]+=u[factor[i][j]]*i/factor[i][j];        }    }}int val[maxn];char ch;void read_int(int & x){    ch=getchar(); x=0;    while(ch<'0'||ch>'9') ch=getchar();    while('0'<=ch&&ch<='9') x=10*x+ch-'0',ch=getchar();}LL num[maxn];LL ans;LL output[maxn];void update(int x,LL sign){    for(int i=0;i<sz[x];++i) {        int y=factor[x][i];        ans=ans+sign*num[y]*w[y];        if(sign<0) ans+=w[y];        num[y]+=sign;    }}void input(){    scanf("%d",&n);    for(int i=0;i<n;++i) read_int(val[i]);    scanf("%d",&Q);    for(int i=0;i<Q;++i) {        read_int(pt[i].x); read_int(pt[i].y);        pt[i].id=i; cpy[i]=pt[i]; --cpy[i].x; --cpy[i].y;    }}void dfs(int id,int l,int r,int fa){    int L=pt[id].x,R=pt[id].y;    int l0=l,r0=r;    while(r0<R) { ++r0; update(val[r0],1); }    while(r0>R) {  update(val[r0],-1); --r0; }    while(l0>L) { --l0; update(val[l0],1); }    while(l0<L) { update(val[l0],-1); ++l0; }    output[id]=ans;    for(Node*p=first[id];p;p=p->next) {        int nxt=p->v;        if(nxt==fa) continue;        dfs(nxt,l0,r0,id);    }    while(r0<r) { ++r0; update(val[r0],1); }    while(r0>r) {  update(val[r0],-1); --r0; }    while(l0>l) { --l0; update(val[l0],1); }    while(l0<l) { update(val[l0],-1); ++l0; }}void solve(){    for(int i=0;i<Q;++i) pt[i]=cpy[i];    dfs(0,pt[0].x,pt[0].x-1,-1);    for(int i=0;i<Q;++i)        printf("%I64d\n",output[i]);}int main(){    pre_init();    int T;cin>>T;    for(int Cas=1;Cas<=T;++Cas) {        ans=0;        input();        MST(Q);        printf("Case #%d:\n",Cas);        solve();    }}




0 0
原创粉丝点击