hdu4777 求区间内与其它数均互质的数的个数(树状数组+离线处理)

来源:互联网 发布:永泰县财政局网络 编辑:程序博客网 时间:2024/05/21 12:48
hdu4777 求区间内与其它数均互质的数的个数
题意:有n(1<=n<=200000)个数字,m(1<=m<=200000)个查询,每次询问[l,r]区间这些数字中,和区间内其他数都互质的数有多少个。
解题思路:
离线处理+树状数组,首先预处理出[1,200000]所有数的质因子,放到have[]里面,然后根据输入的n个数w[],求出每个数的它的质因子
出现的最左位置以及最右位置。然后对m个查询离线,按右边由小到大排序。如第二个样例:
    3   6   1   2   5   3
l[] 0   1   0   2   0   2
r[] 2   4   7   7   7   7
V[] {}  {1} {}  {2}         {3,4,5,6}
明显,求[left,right]区间的结果是(right-left+1-notFit),其中notFit=i的数量(l[i]>=left)+i的数量(r[i]<=right)-i的数量(l[i]>=left && r[i]<=right) ;
可以从左往右扫描,对于第i个,先add(l[i],1),因为左边的notFit数目多了1(自己),然后对V[i]集合里的数x=V[i][j],先add(x,1);因为
x的右边已经超出范围了,所以变为notFit,另外要add(l[x],-1);意思是减去右边notFit的并且左边也notFit的,所以结果就是

sum( right-left+1-( sum(right)-sum(left-1) ) ) 

参考资料:http://blog.csdn.net/ok_again/article/details/15235883

#include<stdio.h>#include<string.h>#include<stdlib.h>#include<math.h>#include<iostream>#include<algorithm>#include<queue>#include<stack>#include<vector>#include<map>#include<set>#include<deque>#include<bitset>#define N 201005using namespace std;int w[N],l[N],r[N];//l[i],r[i]保存第i个数的质因子出现的最左位置以及最右位置vector<int>V[N];//V[i]存储的是j,其中r[j]=ivector<int>have[N],VPrime;//have[i]存储的是数字i分解的质因子,VPrime存储的是[1,200000]的素数int ans[N];//存储结果int flag[N];struct node{    int left,right,id;}p[N];int cmp(node aa,node bb){    return aa.right<bb.right;}int ar[N];int lowb(int t){    return t&(-t);}void add(int i,int v){    if(i==0) return;    for(;i<N;ar[i]+=v,i+=lowb(i));}int sum(int i){    int s=0;    for(;i>0;s+=ar[i],i-=lowb(i));    return s;}void getHave(int index,int v){    int i=0;    while(v>1&&i<VPrime.size())    {        if(VPrime[i]*VPrime[i]>v)        {            have[index].push_back(v);            break;        }        if(i<VPrime.size()&& v%VPrime[i]==0)        {            have[index].push_back(VPrime[i]);        }        while(i<VPrime.size()&& v%VPrime[i]==0)        {            v/=VPrime[i];        }        i++;    }}bool prime[N];void init(){    int i,j;    memset(prime,0,sizeof(prime));    prime[1]=prime[0]=1;    for(i=2;i<=N-2;i++)    for(j=2;i*j<=N-2;j++)    {        prime[i*j]=1;    }    VPrime.clear();    for(i=2;i<=N-2;i++)    {        if(prime[i]==0)            VPrime.push_back(i);    }    for(i=0;i<N;i++)    {        have[i].clear();    }    for(i=2;i<N;i++)    {        getHave(i,i);    }}void init2(int n)//计算出l数组,r数组以及V[]{    for(int i=0;i<=n;i++)    {        V[i].clear();    }    memset(l,0,sizeof(l));    memset(r,0,sizeof(r));    memset(flag,0,sizeof(flag));    for(int i=1;i<=n;i++)    {        int left=0;        for(int j=0;j<have[w[i]].size();j++)        {            left=max(left,flag[have[w[i]][j]]);        }        l[i]=left;        for(int j=0;j<have[w[i]].size();j++)        {            flag[have[w[i]][j]]=i;        }    }    for(int i=1;i<N;i++)//这里要初始化为n+1    {flag[i]=n+1;}    for(int i=n;i>=1;i--)    {        int right=n+1;        for(int j=0;j<have[w[i]].size();j++)        {            right=min(right,flag[have[w[i]][j]]);        }        r[i]=right;        for(int j=0;j<have[w[i]].size();j++)        {            flag[have[w[i]][j]]=i;        }    }    for(int i=1;i<=n;i++)    {        V[r[i]].push_back(i);    }}int main(){    int i,j,k;    int n,m,t;    init();    while(scanf("%d%d",&n,&m)!=EOF&&!(n==0&&m==0))    {        for(i=1;i<=n;i++)        {            scanf("%d",&w[i]);        }        init2(n);        for(i=1;i<=m;i++)        {            scanf("%d%d",&p[i].left,&p[i].right);            p[i].id=i;        }        sort(p+1,p+1+m,cmp);        memset(ar,0,sizeof(ar));        i=1;        for(j=1;j<=m;j++)        {            while(i<=p[j].right)            {                add(l[i],1);//将左边notFit的+1                for(k=0;k<V[i].size();k++)                {                    add(l[V[i][k]],-1);//将左边跟右边同时notFit的-1,去掉重复                    add(V[i][k],1);//将右边notFit的+1                }                i++;            }            int notFit=sum(p[j].right)-sum(p[j].left-1);            ans[p[j].id]=p[j].right-p[j].left+1-notFit;        }        for(i=1;i<=m;i++)        {            printf("%d\n",ans[i]);        }    }}/*input:3 22 1 41 21 36 43 6 1 2 5 31 34 64 42 60 0output:211312*/


0 0
原创粉丝点击