HDU 4407 Sum【容斥原理】

题意: 有n 个数从1 到 n 有序排好,对应两种操作:

          1 x y p  找出区间【x,y】内与 p 互质的数的和

          2 x c     将第x位置的数变成 c

分析:  由于修改的次数比较少,可以先计算出没有修改时候指定区间内与p 互质的数的和,再去根据替换的数去修改,

          找出连续数字区间内与p 互质数的和可以先将p分解质因数,然后用容斥原理快速的计算出区间满足条件的数的

         和即可。

#include<stdio.h>
#include<string.h>
#define clr(x)memset(x,0,sizeof(x))
#define maxn 400005
bool v[maxn];
int pri[maxn];
int top;
void print()
{
    memset(v,true,sizeof(v));
    int i,j;
    top=0;
    pri[top++]=2;
    v[4]=false;
    for(i=3;i<=400000;i++)
    {
        if(v[i])
            pri[top++]=i;
        for(j=0;j<top&&pri[j]*i<=400000;j++)
        {
            v[pri[j]*i]=false;
            if(i%pri[j]==0)
                break;
        }
    }
}
long long get(int now,int n)
{
     long long tmp=(long long)n/now;
     return (long long)now*tmp*(tmp+1)/2;
}
int gcd(int y,int x)
{
    return x==0?y:gcd(x,y%x);
}
long long q[maxn];
long long solve(int n,int p)
{
    int cnt=0;
    int i=0,j;
    while(pri[i]*pri[i]<=p&&i<top)
    {
        int tmp=pri[i];
        if(p%tmp==0)
        {
            q[++cnt]=tmp;
            while(p%tmp==0)
                p/=tmp;
        }
        i++;
    }
    if(p>1)
        q[++cnt]=p;
    int st=1<<cnt;
    long long res;
    res=get(1,n);
    for(i=1;i<st;i++)
    {
        int tmp=1;
        int count=0;
        int now=1;
        for(j=1;j<=cnt;j++)
        {
            if(i&tmp)
            {
                count++;
                now*=q[j];
            }
            tmp<<=1;
        }
        if(count&1)
            res-=get(now,n);
        else
            res+=get(now,n);
    }
    return res;
}
struct node
{
    int xu,x,y;
}ti[maxn];
int id[maxn];
int main()
{
    int i,t,n,m;
    int op;
    print();
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        memset(id,-1,sizeof(id));
        int cnt=0;
        while(m--)
        {
            scanf("%d",&op);
            int x,y,p;
            if(op==1)
            {
                scanf("%d%d%d",&x,&y,&p);
                long long res=0;
                res=solve(y,p);
                res=res-solve(x-1,p);
                for(i=0;i<cnt;i++)
                    if(ti[i].x>=x&&ti[i].x<=y)
                    {
                        int tx=ti[i].x;
                        int ty=ti[i].y;
                        if(gcd(tx,p)==1)
                            res-=tx;
                        if(gcd(ty,p)==1)
                            res+=ty;
                    }
                printf("%I64d\n",res);
            }
            else
            {
                scanf("%d%d",&x,&y);
                if(id[x]==-1)
                {
                    id[x]=cnt;
                    ti[cnt].x=x;
                    ti[cnt++].y=y;
                }
                else
                {
                    ti[id[x]].x=x;
                    ti[id[x]].y=y;
                }
            }
        }
    }
    return 0;
}

 

posted @ 2012-09-24 18:36  'wind  阅读(199)  评论(0编辑  收藏  举报