HDU 6102 GCDispower(容斥原理+数论+树状数组)

来源:互联网 发布:网络在线教育迎着 编辑:程序博客网 时间:2024/06/15 19:11

Description

给出一个1~N的排列PM次查询,每次查询给出一个区间[L,R],求i=LRj=i+1Rk=j+1R[gcd(P[i],P[j])=P[k]]P[k]

Input

第一行一整数T表示用例组数,每组用例首先输入两个证书N,M表示排列长度和查询数,之后输入一个1~N的排列P[i],最后M行每行输入两个整数L,R表示一个查询(1T100,1N,M100000,1LRN)

Output

对于每次查询,输出查询结果

Sample Input

2
3 1
3 2 1
1 3
6 3
6 5 4 3 2 1
1 6
2 6
3 5

Sample Output

1
8
5
0

Solution

离线,固定右端点R,维护每一个左端点L的答案,对于当前加入的点P[R],找到所有下标小于RP[R]的倍数,把这些P[R]的倍数全除以P[R] ,那么对于这些倍数中每一对满足i<j,gcd(P[i],P[j])=1,其对所有左端点L[1,i]的查询的答案贡献均为P[R],因此对于每一个P[R]的倍数P[i],其对查询左端点在[1,i]的答案的贡献为满足ij<R中与P[i]互素的个数乘以P[R],与P[i]互素的数的个数在从右往左扫倍数的时候对素因子容斥得到,对于答案的贡献用树状数组维护即可,对每个数枚举其倍数,对每个倍数要在树状数组中进行两次端点处的更新(前缀和优化区间更新),总时间复杂度O(nlog2n)

Code

#include<cstdio>#include<cstring>#include<algorithm>#include<vector>using namespace std;namespace fastIO {    #define BUF_SIZE 100000    //fread -> read    bool IOerror=0;    inline char nc()     {        static char buf[BUF_SIZE],*p1=buf+BUF_SIZE,*pend=buf+BUF_SIZE;        if(p1==pend)         {            p1=buf;            pend=buf+fread(buf,1,BUF_SIZE,stdin);            if(pend==p1)             {                IOerror=1;                return -1;            }        }        return *p1++;    }    inline bool blank(char ch)     {        return ch==' '||ch=='\n'||ch=='\r'||ch=='\t';    }    inline void read(int &x)     {        char ch;        while(blank(ch=nc()));        if(IOerror)return;        for(x=ch-'0';(ch=nc())>='0'&&ch<='9';x=x*10+ch-'0');    }    inline void readc(char &x)    {        char ch;        while(blank(ch=nc()));        if(IOerror)return;        x=ch;    }    #undef BUF_SIZE};using namespace fastIO;typedef long long ll;typedef pair<int,int>P;const int maxn=100001;int T,n,m,p[maxn],pos[maxn],num[maxn],temp[maxn];ll ans[maxn];vector<P>fact[maxn],q[maxn];vector<int>pri[maxn];int mark[maxn];struct BIT{    #define lowbit(x) (x&(-x))    ll b[maxn];    void init()    {        memset(b,0,sizeof(b));    }    void add(int x,ll v)    {        while(x<=n)            b[x]+=v,x+=lowbit(x);    }    ll sum(int x)    {        ll ans=0;        while(x)            ans+=b[x],x-=lowbit(x);        return ans;    }}bit;void init(int n=100000){    for(int i=2;i<=n;i++)        if(!mark[i])            for(int j=i;j<=n;j+=i)                mark[j]=1,pri[j].push_back(i);    for(int i=1;i<=n;i++)    {           int N=1<<pri[i].size();        for(int j=0;j<N;j++)        {            fact[i].push_back(P(1,1));            for(int k=0;k<pri[i].size();k++)                if(j&(1<<k))                    fact[i][j].first*=pri[i][k],fact[i][j].second*=-1;        }    } }ll Count(int x){    ll ans=0;    for(int i=0;i<fact[x].size();i++)        ans+=num[fact[x][i].first]*fact[x][i].second;    return ans;}void Deal(int x,int v){    for(int i=0;i<fact[x].size();i++)        num[fact[x][i].first]+=v;}int main(){    init();    read(T);    //scanf("%d",&T);    while(T--)    {        bit.init();        //scanf("%d%d",&n,&m);        read(n),read(m);        for(int i=1;i<=n;i++)        {            read(p[i]);            //scanf("%d",&p[i]);            pos[p[i]]=i,q[i].clear();        }        for(int i=1;i<=m;i++)        {            int l,r;            read(l),read(r);            //scanf("%d%d",&l,&r);            q[r].push_back(P(l,i));        }        for(int i=1;i<=n;i++)        {            int res=0;            for(int j=2*p[i];j<=n;j+=p[i])                if(pos[j]<i)temp[++res]=pos[j];            sort(temp+1,temp+res+1);            for(int j=res;j>=1;j--)            {                ll sum=Count(p[temp[j]]/p[i])*p[i];                bit.add(1,sum),bit.add(temp[j]+1,-sum);                Deal(p[temp[j]]/p[i],1);            }            for(int j=1;j<=res;j++)Deal(p[temp[j]]/p[i],-1);            for(int j=0;j<q[i].size();j++)                ans[q[i][j].second]=bit.sum(q[i][j].first);        }        for(int i=1;i<=m;i++)printf("%I64d\n",ans[i]);    }    return 0;}
原创粉丝点击